sunebrodersen
sunebrodersen

Reputation: 309

Updating multiple embedded docs in mongoDB

I need to update multiple embedded docs in mongo using PHP. My layout looks like this:

{
  _id: id,
  visits : {
        visitID: 12
        categories: [{
              catagory_id: 1,
              name: somename,
              count: 11,
              duration: 122
              },
              {
              catagory_id: 1,
              name: some other name,
              count: 11,
              duration: 122
              },
              {
              catagory_id: 2,
              name: yet another name,
              count: 11,
              duration: 122
              }]
   }
}

The document can have more than one visit too.

Now i want to update 2 categories, one with id=1 and name=somename and the other with id=1 and name=some_new_name. Both of them should inc "count" by 1 and "duration" by 45.

First document exists, but second does not.

Im thinking of having a function like this:

function updateCategory($id, $visitID,$category_name,$category_id) {

    $this->profiles->update(
            array(
                '_id' => $id, 
                'visits.visitID' => $visitID,
                'visits.categories.name' => $category_name,
                'visits.categories.id' => $category_id,
            ), 
            array(
                '$inc' =>   array(
                            'visits.categories.$.count' => 1,
                            'visits.categories.$.duration' =>45,
                        ),
            ), 
            array("upsert" => true)
    );  
}   

But with this i need to call the function for each category i will update. Is there any way to do this in one call?

EDIT:

Changed the layout a bit and made "categories" an object instead of array. Then used a combination of "category_id" and "category_name" as property name. Like:

categories: {
              1_somename : {
                  count: 11,
                  duration: 122
              },
              1_some other name : {
                  count: 11,
                  duration: 122
              },
              2_yet another name : {
                  count: 11,
                  duration: 122
              },
}

Then with upsert and something like

$inc: {
 "visits.$.categories.1_somename.d": 100,
 "visits.$.categories.2_yet another name.c": 1
}

i can update several "objects" at a time..

Upvotes: 1

Views: 1207

Answers (1)

Andrew Orsich
Andrew Orsich

Reputation: 53675

Mongodb currently not supporting arrays multiple levels deep updating (jira)

So following code will not work:

'$inc' =>      array( 
   'visits.categories.$.count' => 1, 
   'visits.categories.$.duration' => 123, 
 ),

So there is some solutions around this:

1.Load document => update => save (possible concurrency issues)
2.Reorganize your documents structure like this(and update using one positional operator):

{
  _id: id,
  visits : [{
        visitID: 12
  }],
  categories: [{
              catagory_id: 1,
              name: somename,
              count: 11,
              duration: 122,
              visitID: 12
              }]
   }
}

3.Wait for multiple positional operators support (planning in 2.1 version of mongodb).
4.Reorganize your documents structure somehow else, in order to avoid multiple level arrays nesting.

Upvotes: 1

Related Questions