简体   繁体   中英

Insert into the front of a MongoDB document array without $position and $each?

When deploying a meteor app to a sandbox MongoDB that isn't updated to Mongo 3.0 i can't use the $position and $each queries.

Is there another way to achieve what i am doing with these queries?

I want to add a task to the front of the array.

Here is the code in the method:

newTask: function(task, date, number) {

    if (! Meteor.userId()) {
        throw new Meteor.Error("not-authorized");
    }

    if(number === 0){
        projectsDB.update({user: Meteor.user()._id}, {$push: {'panels.0.tasks': { $each: [{name: task, date: date}], $position: 0}}})
    } else if(number === 1){
        projectsDB.update({user: Meteor.user()._id}, {$push: {'panels.1.tasks': { $each: [{name: task, date: date}], $position: 0}}})
    } else if(number === 2){
        projectsDB.update({user: Meteor.user()._id}, {$push: {'panels.2.tasks': { $each: [{name: task, date: date}], $position: 0}}})
    } else if(number === 3){
        projectsDB.update({user: Meteor.user()._id}, {$push: {'panels.3.tasks': { $each: [{name: task, date: date}], $position: 0}}})
    }
}

But essentially how could I recreate

projectsDB.update({user: Meteor.user()._id}, {$push: {'panels.3.tasks': { $each: [{name: task, date: date}], $position: 0}}})

without use $position and $each ?

I actually thought this was quite simple really, and commented but then thought about it and it's really an answer.

It depends on which case actually suits but there are two alternates here.

  1. Just continue adding items to the array with a standard $push operation. This just "appends" ( rather than pre-pend ) to the the array always anyhow.

     projectsDB.update( { user: Meteor.user()._id }, { $push: { 'panels.0.tasks': { name: task, date: date } }} ) 

    So no worries about supported modifiers there, as all new entries just go to the back rather than the front.

    But when you read the data back then all you need to do is apply JavaScript .reverse() to the array. The construct is simple, just either put it in a helper or within something to "publish" as required:

     var projects = projectsDB.find(query).fetch(); projects.forEach(function(project) { project.panels.forEach(function(panel) { panel.tasks.reverse(); // reverses the order }); }) 

    You just need to be aware if you "publish" like that to pre-process the .reverse() again before appending anything else. So probably better suited to a display helper only.

  2. Since I see a "date" in there, it would seem logical that you want the "newest task" to be the first listed. So all you really need to do here is apply the $sort modifier which is already supported:

     projectsDB.update( { user: Meteor.user()._id }, { $push: { 'panels.0.tasks': { $each: [{name: task, date: date}], $sort: { date: -1 } }} } ) 

    Then the "newest" entry will always be at the "front" as the list is "sorted" by the date property on every update. Not sure if the meteor version or the MongoDB version you have supports $sort without a $slice modifier as well. If required just either set that to your required maximum size or a number larger than the maximum expected entries so it does not have an effect in the latter case.

The $position modifier itself was intended for much wider usage than simply "pre-pending" to an array, so there have always been other ways to achieve the same thing, before it's introduction.

As of writing I believe this is yet to make it into "minimongo" anyway, so regarless of the server version, any client side code would not be able to use the operator. But the two above choices certainly will work client side.

From your past question edits, this is what the server prompted: MongoError: $each term takes only $slice (and optionally $sort) as complements .

Remove $position as it has only been introduced in MongoDB 2.6 and try this hack using negative indexes:

{
  $set: {
     'panels.0.tasks.-1': {name: task, date: date}
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM