0

i want to know the difference between this 2 query:

myCollection.update (    {
      a:1,
      b:1,
      $isolated:1    } );

myCollection.update (    {
      $and:
      [ 
        {a:1},
        {b:1},
        {$isolated:1}
      ]    } );

Basically i need to perform an .update() with $isolated for all the documents that have 'a=1 and b=1'. I'm confusing about how to write the '$isolated' param and how to be sure that the query work fine.

Blakes Seven
  • 49,422
  • 14
  • 129
  • 135
Daniele Tassone
  • 2,104
  • 2
  • 17
  • 25
  • According to [the documentation](http://docs.mongodb.org/manual/reference/operator/update/isolated/) you would use the first variant. The second seems needlessly complex to do the same. I am not sure how it behaves, but if you *have* to use $and or other operators for some reason (here you don't) I *think* it would be more correct to put $isolated on the first level, e.g. `{ $and: [ ....stuff ... ] , $isolated:true }` – Philipp Aug 29 '15 at 08:19

1 Answers1

3

I would basically question the "need to perform" of your statement, especially considering lack of { multi: true } where you intend to match and update a lot of documents.

The second consideration here is that your proposed statement(s) lack any kind of update operation at all. That might be a consquence of the question you are asking about the "difference", but given your present apparent understanding of MongoDB query operations with relation to the usage of $and, then I seriously doubt you "need" this at all.

So "If" you really needed to write a statement this way, then it should look like this:

myCollection.update(
   { "a": 1, "b": 1, "$isolated": true },
   { "$inc": { "c": 1 } },
   { "multi": true }
)

But what you really "need" to understand is what that is doing.

Essentially this query is going to cause MongoDB to hold a "write lock", and at least on the collection level. So that no other operations can be performed until the entire wtite is complete. This also ensures that until that time, then all read attempts will only see the state of the document before any changes were made, until that operation is complete in full and then subsequent reads see all the changes.

This may "sound tempting", to be a good idea to some, but it really is not. Write locks affect the concurrency of updates and a generally a bad thing to be avoided. You might also be confusing this with a "transaction" but it is not, and as such any failure during the execution will only halt the operations at the point where it failed. This does not "undo" changes made within the $isolated block, and they will remain committed.

Just about the only valid use case here, would be where you "absolutely need", all of the elements to be modified matching "a" and "b" to maintain a consistent state in the event that something was "aggregating" that combination at the exact same time as this operation was run. In that case, then exposing "partially" altered values of "c" may not be desirable. But the range of usage of this is pretty slim, and most general applications do not require such consistency.

Back to the usage of $and, well all MongoDB arguments are implicitly an $and operation anyway, unless they are explicitly stated. The only general usage for $and is where you need multiple conditions on the same document key. And even then, that is generally better written on the "right side" of evaluation, such as with $gt and $lt:

{ "a": { "$gt": 1, "$lt": 3 } }

Being exactly the same as:

{
    "$and": [
        { "a": { "$gt": 1 } },
        { "b": { "$lt": 3 } }
    ]
}

So it's really quite superfluous.

In the end, if all you really want to do is:

myCollection.update(
   { "a": 1, "b": 1 },
   { "$inc": { "c": 1 } },
)

Updating a single document, then there is no need for $isolated at all. Obtaining an explicit lock here is really just providing complexity to an otherwise simple operation that is not required. And even in bulk, you likely really do not need the consistency that is provided by obtaining the lock, and as such can simple do again:

myCollection.update(
   { "a": 1, "b": 1 },
   { "$inc": { "c": 1 } },
   { "multi": true }
)

Which will hapilly yield to allow writes on all selected documents and reads of the "latest" information. Generally speaking, "you want this" as "atomic" operators such as $inc are just going to modify the present value they see anyway.

So it does not matter if another process matched one of these documents before the "multi" write found that document in all the matches, since "both" $inc operations are going to execute anyway. All $isolated really does here is "ensure" that when this operation is started, then "it's" write will be the "first" committed, and then anything attempted during the lock will happen "after", as opposed to just the general order of when each operation is able to grab that document and make the modification.

In 9/10 cases, the end result is the same. The exception being that the "write lock" obtained here, "will" slow down other operations.

Blakes Seven
  • 49,422
  • 14
  • 129
  • 135
  • Blakes thank you. My problem is easy. I have an collection of 1.000 document and i need two-step commit. So in the first Update() i will make an "status:'processing''. After that i can work locally (nodeJS) the value and i will made another Update() with 'status:'available'' for the next query. – Daniele Tassone Aug 29 '15 at 09:26
  • What you write have sense, i know the Lock level. The problem is that i don't have any other solution. – Daniele Tassone Aug 29 '15 at 09:27
  • @Dada Your basic description here ( which is not the question you asked anyway ) does nothing really to convince me that you need this at all. All I see is your "perception" that you need this. And very much as I have said, if you don't yet understand when to use `$and` then I do find it likely you yet understand when you "need" `$isolated`. How about you "try" doing your operation without it. Then if you think problems are happening then try with `$isolated`. But very much doubt if any problems are occurring here then that will fix it. Your actual process should probably be another question. – Blakes Seven Aug 29 '15 at 09:30
  • Bakes, i understand your point. If i have 10 query at same time, that need to update a group of documents, how i can be sure that only the 'first query' make the job? I can use "findAndModify", but my concern is that if each 'findAndModify' is atomic. As i know isn't, because findAndModify is "atomic-for-document'. Then if potentially the query has a target of 1.000 documents and i run 10-query, then maybe the query n.5 will some of 1.000 documents. What i want is that query-1 came first, then take the responsability over all the 1.000 Documents. – Daniele Tassone Aug 29 '15 at 09:41
  • @Dada My main point here was to "answer the question you asked" which was primarily "which syntax do I use" and also augment that with some of the usage case and caveats of `$isolated` and the usage of `$and` in general since it seemed valid to me if you did not understand `$and` then you were diving into `$isolated` with a blindfold on. But that question is answered. If you have additional questions then please [Ask Another Question](http://stackoverflow.com/questions/ask) about that topic explicitly. That is how it works here. – Blakes Seven Aug 29 '15 at 09:45
  • @Dada And I did see your "update". Doing such a thing and essentially asking a different question after you already have an answer to your original question is not considered good behavoir here. Please revert to your original question and ask another instead. – Blakes Seven Aug 29 '15 at 09:47