0

I have this data in Mongo:

{'_id':1,
             'name':'Root',
             'taskId':1,
             'parentId':"",
             'path':[1],
             'tasks':[  {"taskId":3,parentId:1,name:'A',type:'task'},
                        {"taskId":4,parentId:1,name:'D',type:'task'},
                        {"taskId":5,parentId:4,name:'B',type:'task'},
                        {'type':'project' , 'proRef':2},
                        {"taskId":6,parentId:3,name:'E',type:'task'},
                        {"taskId":7,parentId:6,name:'C',type:'task'}]

            }

Now I want to update taskId 6 with new Json data .

var jsonData = {"taskId":6,"name":'Sumeet','newField1':'Val1','newField2':'Val2'}

query should update if field is available else add new key to existing .Output Like

{"taskId":6,parentId:3,name:'Sumeet',type:'task','newField1':'Val1','newField2':'Val2'}]

I have tried few query but it is completely replacing json .

 db.projectPlan.update({_id:1,'tasks.taskId':6},{$set :{'tasks.$':jsonData }});

Thanks in advance for your helps! Sumeet

3
  • Please suggest if it is not possible also. Commented Dec 12, 2013 at 18:58
  • 1
    That's strange. According to the documentation it should work. Commented Dec 12, 2013 at 20:50
  • Indeed this query will only replace the task with taskId 6. It will not merge the existing data with the new data. See my solution below for how the data can be merged. Commented Dec 12, 2013 at 21:17

2 Answers 2

5

You need to transform the jsonData variable into something that can be passed to update. Here's an example that does exactly what you want with your sample document:

var updateData = {};
for (f in jsonData) {
    if (f != "taskId") updateData["tasks.$."+f]=jsonData[f]; 
};
db.projectPlan.update({_id:1, 'tasks.taskId':6}, {$set:updateData})

Result:

{ "_id" : 1, 
  "name" : "Root",
  "taskId" : 1,
  "parentId" : "",
  "path" : [  1 ],
  "tasks" : [
    {   "taskId" : 3,   "parentId" : 1,     "name" : "A",   "type" : "task" },
    {   "taskId" : 4,   "parentId" : 1,     "name" : "D",   "type" : "task" },
    {   "taskId" : 5,   "parentId" : 4,     "name" : "B",   "type" : "task" },
    {   "type" : "project",     "proRef" : 2 },
    {   "taskId" : 6,   "parentId" : 3,     "name" : "Sumeet",  "type" : "task",    "newField1" : "Val1",   "newField2" : "Val2" },
    {   "taskId" : 7,   "parentId" : 6,     "name" : "C",   "type" : "task" } 
] }
Sign up to request clarification or add additional context in comments.

Comments

1

You will need to merge the document manually:

var jsonData = {"taskId":5,"name":'Sumeet','newField1':'Val1','newField2':'Val2'};

db.projectPlan.find({ _id: 1 }).forEach(
  function(entry) {
    for (var taskKey in entry.tasks) {
      if (entry.tasks[taskKey].taskId === jsonData.taskId) {
        printjson(entry.tasks[taskKey]);
        for (var taskSubKey in jsonData) {
           entry.tasks[taskKey][taskSubKey] = jsonData[taskSubKey];
        }
        printjson(entry.tasks[taskKey]);
      }
    }
    db.projectPlan.save(entry);
  }
);

Obviously you can leave away the printjson statements. This is simply to see that the merging of the original tasks with the new tasks works. Note that this query will only update a single document as long as the _id field is unique.

6 Comments

this is completely unnecessary - why would you need to look at every single document?
this solution only looks at documents with '_id: 1'. Usually this field has index support. So this query will be fast.
then why have all the javascript to do the update when it can be done atomically and thread-safe on the server? If your code is run twice, it may lose one of the update's changes since your query and your save are not atomic.
If the same code runs twice, the answer will be the same since the operation is idempotent (only if the input stays the same). Yet I agree that atomicity is a plus, and therefore I like your solution. This solution is, however, more extensible.
I'm talking about two threads trying to update the same object (but different tasks of the same object). They will both read the document and then both save and the one that saves second will overwrite the changes of the first one.
|

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.