0

There are 10000 docs import by mongoimport, the _id is 6 length random string

{_id:"xxxxxx","u":0,"t":0}

because mongoimport can not specifiy data type, so string like "123456" was imported as type int. So I manually delete originals and re-insert them as

db.xxx.insert({_id:"123456","u":0,"t":0})

Because the default type of 0 is Double, so I change them to int by:

db.xxx.update({},{$set:{u:NumberInt(0)}},false,true)
WriteResult({ "nMatched" : 100000, "nUpserted" : 0, "nModified" : 99994 })

Seems 6 docs change failed, I validate the change by:

> db.code.find({u:{$type:1}})
{ "_id" : "263798", "t" : 4, "u" : 0 }
{ "_id" : "375249", "t" : 7, "u" : 0 }
{ "_id" : "659472", "t" : 3, "u" : 0 }
{ "_id" : "672534", "t" : 3, "u" : 0 }
{ "_id" : "784392", "t" : 0, "u" : 0 }
{ "_id" : "875631", "t" : 0, "u" : 0 }

the update only modify docs which was imported by mongoimport but leave alone docs which I manually insert, why?

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
jean
  • 2,825
  • 2
  • 35
  • 72

1 Answers1

3

It's not a failure but by design.

Under the Bulk Operations API, if you supply a value to update that matches an existing value of the document then it is not marked as modified and actually does not make any attempt to re-write the document.

Simple test:

db.junk.insert({ "a": 1 })
WriteResult({ "nInserted" : 1 })

db.junk.update({ "a": 1},{ "$set": { "a": 2 }})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

db.junk.update({ "a": 2 },{ "$set": { "a": 2 }})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })

db.junk.update({ "a": 2 },{ "$set": { "a": NumberInt(2) }})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

db.junk.update({ },{ "$set": { "a": NumberInt(2) }})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })

All operations in the MongoDB shell as of version 2.6 are actually using the Bulk Operations API. This is where you see the WriteResult which comes from that API as proof this is happening.

So the short case here is if you have "manually inserted" items that are of the correct type you are modifying to, then they do not get changed.

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
  • mongodb decide modify or not is according to value but don't consider value'type. Does this also apply to all mongodb drivers? – jean Jan 09 '15 at 09:45
  • @jean I made it a bit clearer to the "type" case. But it is true of all drivers using the "Bulk API" which most do not by default unless you explicitly call those methods. Standard driver `.update()` methods return a "legacy write concern" response which would report the document as modified even if there was no change. The shell will use the Bulk methods and report the items you added with correct integer types and `0` value to be "unmodified". – Neil Lunn Jan 09 '15 at 09:48
  • your third update success? whatever I try, I can not change the type without change the value by mongod – jean Jan 09 '15 at 10:13
  • @jean I'm not sure what you mean here. Can you explain more clearly. I'm just demonstrating how `WriteResult` responses come out and how not everything matched is modified if it does not need to be. – Neil Lunn Jan 09 '15 at 10:19
  • I mean "db.junk.update({ "a": 2 },{ "$set": { "a": NumberInt(2) }})" should not success, because a's value already is 2 – jean Jan 14 '15 at 03:19
  • @jean What I am pointing out here is that "Integer" and "Double" are not the same type. The "generic" `{ "a": 2 }` as a search will match both, but the update will only overwrite a "Double" and the "Integer" value would stay untouched. Hence the difference in counters. – Neil Lunn Jan 14 '15 at 03:22