14

Mongo supports arrays of documents inside documents. For example, something like

{_id: 10, "coll": [1, 2, 3] }

Now, imagine I wanted to insert an arbitrary value at an arbitrary index

{_id: 10, "coll": [1, {name: 'new val'}, 2, 3] }

I know you can update values in place with $ and $set, but nothing for insertion. it kind of sucks to have to replace the entire array just for inserting at a specific index.

0

5 Answers 5

20

Starting with version 2.6 you finally can do this. You have to use $position operator. For your particular example:

db.students.update(
  { _id: 10},
  { $push: {
     coll: {
       $each: [ {name: 'new val'} ],
       $position: 1
     }
  }}
)
Sign up to request clarification or add additional context in comments.

Comments

1

The following will do the trick:

var insertPosition = 1;
var newItem = {name: 'new val'};

db.myCollection.find({_id: 10}).forEach(function(item)
{
    item.coll = item.coll.slice(0, insertPosition).concat(newItem, item.coll.slice(insertPosition));
    db.myCollection.save(item);
});

If the insertPosition is variable (i.e., you don't know exactly where you want to insert it, but you know you want to insert it after the item with name = "foo", just add a for() loop before the item.coll = assignment to find the insertPosition (and add 1 to it, since you want to insert it AFTER name = "foo".

Comments

1

Handy answer (not selected answer, but highest rated) from this similar post: Can you have mongo $push prepend instead of append?

utilizes $set to insert 3 at the first position in an array, called "array". Sample from related answer by Sergey Nikitin:

db.test.update({"_id" : ObjectId("513ad0f8afdfe1e6736e49eb")}, 
                 {'$set': {'array.-1':     3}})

Comments

0

Regarding your comment:

Well.. with concurrent users this is going to be problematic with any database...

What I would do is the following: Add a last modified timestamp to the document. Load the document, let the user modify it and use the timstamp as a filter when you update the document and also update the timestamp in one step. If it updates 0 documents you know it was modified in the meantime and you can ask the user to reload it.

Comments

0

Using the $position operator this can be done starting from version 2.5.3.

It must be used with the $each operator. From the documentation:

db.collection.update( <query>,
                  { $push: {
                              <field>: {
                                         $each: [ <value1>, <value2>, ... ],
                                         $position: <num>
                              }
                           }
                  }
                )

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.