Updating documents

db.update(query, update, options, callback) will update all documents matching query according to the update rules:

  • query is the same kind of finding query you use with find and findOne
  • update specifies how the documents should be modified. It is either a new document or a set of modifiers (you cannot use both together, it doesn't make sense!)
    • A new document will replace the matched docs
    • The modifiers create the fields they need to modify if they don't exist, and you can apply them to subdocs. Available field modifiers are $set to change a field's value, $unset to delete a field, $inc to increment a field's value and $min/$max to change field's value, only if provided value is less/greater than current value. To work on arrays, you have $push, $pop, $addToSet, $pull, and the special $each and $slice. See examples below for the syntax.
  • options is an object with two possible parameters
    • multi (defaults to false) which allows the modification of several documents if set to true
    • upsert (defaults to false) if you want to insert a new document corresponding to the update rules if your query doesn't match anything. If your update is a simple object with no modifiers, it is the inserted document. In the other case, the query is stripped from all operator recursively, and the update is applied to it.
    • returnUpdatedDocs (defaults to false, not MongoDB-compatible) if set to true and update is not an upsert, will return the array of documents matched by the find query and updated. Updated documents will be returned even if the update did not actually modify them.
  • callback (optional) signature: (err, numAffected, affectedDocuments, upsert). Warning: the API was changed between v1.7.4 and v1.8. Please refer to the change log to see the change.
    • For an upsert, affectedDocuments contains the inserted document and the upsert flag is set to true.
    • For a standard update with returnUpdatedDocs flag set to false, affectedDocuments is not set.
    • For a standard update with returnUpdatedDocs flag set to true and multi to false, affectedDocuments is the updated document.
    • For a standard update with returnUpdatedDocs flag set to true and multi to true, affectedDocuments is the array of updated documents.

Note: you can't change a document's _id.

  1. // Let's use the same example collection as in the "finding document" part
  2. // { _id: 'id1', planet: 'Mars', system: 'solar', inhabited: false }
  3. // { _id: 'id2', planet: 'Earth', system: 'solar', inhabited: true }
  4. // { _id: 'id3', planet: 'Jupiter', system: 'solar', inhabited: false }
  5. // { _id: 'id4', planet: 'Omicron Persia 8', system: 'futurama', inhabited: true }
  6. // Replace a document by another
  7. db.update({ planet: 'Jupiter' }, { planet: 'Pluton'}, {}, function (err, numReplaced) {
  8. // numReplaced = 1
  9. // The doc #3 has been replaced by { _id: 'id3', planet: 'Pluton' }
  10. // Note that the _id is kept unchanged, and the document has been replaced
  11. // (the 'system' and inhabited fields are not here anymore)
  12. });
  13. // Set an existing field's value
  14. db.update({ system: 'solar' }, { $set: { system: 'solar system' } }, { multi: true }, function (err, numReplaced) {
  15. // numReplaced = 3
  16. // Field 'system' on Mars, Earth, Jupiter now has value 'solar system'
  17. });
  18. // Setting the value of a non-existing field in a subdocument by using the dot-notation
  19. db.update({ planet: 'Mars' }, { $set: { "data.satellites": 2, "data.red": true } }, {}, function () {
  20. // Mars document now is { _id: 'id1', system: 'solar', inhabited: false
  21. // , data: { satellites: 2, red: true }
  22. // }
  23. // Not that to set fields in subdocuments, you HAVE to use dot-notation
  24. // Using object-notation will just replace the top-level field
  25. db.update({ planet: 'Mars' }, { $set: { data: { satellites: 3 } } }, {}, function () {
  26. // Mars document now is { _id: 'id1', system: 'solar', inhabited: false
  27. // , data: { satellites: 3 }
  28. // }
  29. // You lost the "data.red" field which is probably not the intended behavior
  30. });
  31. });
  32. // Deleting a field
  33. db.update({ planet: 'Mars' }, { $unset: { planet: true } }, {}, function () {
  34. // Now the document for Mars doesn't contain the planet field
  35. // You can unset nested fields with the dot notation of course
  36. });
  37. // Upserting a document
  38. db.update({ planet: 'Pluton' }, { planet: 'Pluton', inhabited: false }, { upsert: true }, function (err, numReplaced, upsert) {
  39. // numReplaced = 1, upsert = { _id: 'id5', planet: 'Pluton', inhabited: false }
  40. // A new document { _id: 'id5', planet: 'Pluton', inhabited: false } has been added to the collection
  41. });
  42. // If you upsert with a modifier, the upserted doc is the query modified by the modifier
  43. // This is simpler than it sounds :)
  44. db.update({ planet: 'Pluton' }, { $inc: { distance: 38 } }, { upsert: true }, function () {
  45. // A new document { _id: 'id5', planet: 'Pluton', distance: 38 } has been added to the collection
  46. });
  47. // If we insert a new document { _id: 'id6', fruits: ['apple', 'orange', 'pear'] } in the collection,
  48. // let's see how we can modify the array field atomically
  49. // $push inserts new elements at the end of the array
  50. db.update({ _id: 'id6' }, { $push: { fruits: 'banana' } }, {}, function () {
  51. // Now the fruits array is ['apple', 'orange', 'pear', 'banana']
  52. });
  53. // $pop removes an element from the end (if used with 1) or the front (if used with -1) of the array
  54. db.update({ _id: 'id6' }, { $pop: { fruits: 1 } }, {}, function () {
  55. // Now the fruits array is ['apple', 'orange']
  56. // With { $pop: { fruits: -1 } }, it would have been ['orange', 'pear']
  57. });
  58. // $addToSet adds an element to an array only if it isn't already in it
  59. // Equality is deep-checked (i.e. $addToSet will not insert an object in an array already containing the same object)
  60. // Note that it doesn't check whether the array contained duplicates before or not
  61. db.update({ _id: 'id6' }, { $addToSet: { fruits: 'apple' } }, {}, function () {
  62. // The fruits array didn't change
  63. // If we had used a fruit not in the array, e.g. 'banana', it would have been added to the array
  64. });
  65. // $pull removes all values matching a value or even any NeDB query from the array
  66. db.update({ _id: 'id6' }, { $pull: { fruits: 'apple' } }, {}, function () {
  67. // Now the fruits array is ['orange', 'pear']
  68. });
  69. db.update({ _id: 'id6' }, { $pull: { fruits: $in: ['apple', 'pear'] } }, {}, function () {
  70. // Now the fruits array is ['orange']
  71. });
  72. // $each can be used to $push or $addToSet multiple values at once
  73. // This example works the same way with $addToSet
  74. db.update({ _id: 'id6' }, { $push: { fruits: { $each: ['banana', 'orange'] } } }, {}, function () {
  75. // Now the fruits array is ['apple', 'orange', 'pear', 'banana', 'orange']
  76. });
  77. // $slice can be used in cunjunction with $push and $each to limit the size of the resulting array.
  78. // A value of 0 will update the array to an empty array. A positive value n will keep only the n first elements
  79. // A negative value -n will keep only the last n elements.
  80. // If $slice is specified but not $each, $each is set to []
  81. db.update({ _id: 'id6' }, { $push: { fruits: { $each: ['banana'], $slice: 2 } } }, {}, function () {
  82. // Now the fruits array is ['apple', 'orange']
  83. });
  84. // $min/$max to update only if provided value is less/greater than current value
  85. // Let's say the database contains this document
  86. // doc = { _id: 'id', name: 'Name', value: 5 }
  87. db.update({ _id: 'id1' }, { $min: { value: 2 } }, {}, function () {
  88. // The document will be updated to { _id: 'id', name: 'Name', value: 2 }
  89. });
  90. db.update({ _id: 'id1' }, { $min: { value: 8 } }, {}, function () {
  91. // The document will not be modified
  92. });