mongodb micro-optimization of batch inserts ? or is this an important optimization?

278 views Asked by At

premise : update statements are harmless since the driver by default works in one way messaging (as long as getLastError isn't used).

question Is the following fragment the best way to do this in mongodb for high volume inserts ? Is it possible to fold step 2 and 3 ?

edit : old buggy form , see below

// step 1 : making sure the top-level document is present (an upsert in the real 
            example)
db.test.insert( { x :1} )

// step 2 : making sure the sub-document entry is present
db.test.update( { x:1 }, { "$addToSet" : { "u" : { i : 1, p : 2 } } }, false)

// step 3 : increment a integer within the subdocument document
db.test.update( { x : 1, "u.i" : 1}, { "$inc" : { "u.$.c" : 1 } },false)

I have a feeling there is no way out of operation 3, since the$ operator requires priming in the query field of the query part of an update. amirite ? iamrite ?

If this is the best way to do things, can I get creative in my code and go nuts with update operations ?

edit : new form

There was a bug in my logic, thanks Gates. Still want to fold the updates if possible :D

// make sure the top-level entry exists and increase the incidence counter
db.test.update( { x : 1 }, { $inc : { i : 1 } }, true ) --1

// implicetly creates the array
db.test.update(   { x : 1 , u : { $not : { $elemMatch : { i : 1 } } } } , 
                  { $push : { u : { i : 1 , p :2 , c:0} } }) -- 2

db.test.update( { x :1 , "u.i" : 1}, { $inc : { "u.$.c" : 1 } },false) --3

notes : $addToSet is not usefull in this case, since it does a element-wise match, there is no way to express what elements in an array may be mutable as in C++ OO bitwise comparison parlance

question is pointless Data model is wrong. Please vote to close (OP).

1

There are 1 answers

1
Gates VP On

So, the first thing to note is that the $ positional operator is a little sketchy. It has a lot of "gotchas": it doesn't play well with upserts, it only affects the first true match, etc.

To understand "folding" of #2 and #3, you need to look at the output of your commands:

db.test.insert( { x :1} )
{ x:1 } // DB value

db.test.update( { x:1 }, { "$addToSet" : { "u" : { i : 1, p : 2 } } }, false)
{ x:1, u: [ {i:1,p;2} ] } // DB value

db.test.update( { x : 1, "u.i" : 1}, { "$inc" : { "u.$.c" : 1 } },false)
{ x:1, u: [ {i:1,p:2,c:1} ] } // DB value

Based on the sequence you provided, the whole thing can be rolled into a single update.

If you're only looking to roll together #2 & #3, then you're worried about matching 'u.i':1 with u.$.c. But there are some edge cases here you have to clarify.

Let your starting document be the following:

{ 
  x:1, 
 u: [ 
      {i:1, p:2},
      {i:1, p:3}  
    ] 
}

What do you expect from running update #3?

As written you get:

{ 
  x:1, 
 u: [ 
      {i:1, p:2, c:1},
      {i:1, p:3}  
    ] 
}

Is this correct? Is that first document legal? (semantically correct)? Depending on the answers, this may actually be an issue of document structure.