findAndModify

在本页面

定义

  • findAndModify

    • findAndModify命令修改并返回单个文档。默认情况下,返回的文档不包括对更新所做的修改。要使用更新中所做的修改_return 文档,请使用new选项。

该命令具有以下语法:

{
  findAndModify: <collection-name>,
  query: <document>,
  sort: <document>,
  remove: <boolean>,
  update: <document>,
  new: <boolean>,
  fields: <document>,
  upsert: <boolean>,
  bypassDocumentValidation: <boolean>,
  writeConcern: <document>,
  collation: <document>,
  arrayFilters: <array>
}

findAndModify命令采用以下字段:

领域类型描述
query文献可选的。修改的选择标准。 query字段使用与db.collection.find()方法中使用的query selectors相同的query selectors。虽然查询可能匹配多个文档,但findAndModify 只会选择一个文档来修改
如果未指定,则默认为空文档。
从 MongoDB 3.6.14(和 3.4.23)开始,如果查询参数不是文档,则操作错误。
sort文献可选的。如果查询选择多个文档,则确定操作修改的文档。 findAndModify修改此参数指定的 sort order 中的第一个文档。
从 MongoDB 3.6.14(和 3.4.23)开始,如果 sort 参数不是文档,则操作错误。
removeboolean必须指定removeupdate字段。删除query字段中指定的文档。将其设置为true以删除所选文档。默认值为false
update文献必须指定removeupdate字段。执行所选文档的更新。 update字段使用相同的更新 operatorsfield: value规范来修改所选文档。
newboolean可选的。当true时,返回修改后的文档而不是原始文档。 findAndModify方法忽略remove操作的new选项。默认值为false
fields文献可选的。 return 的字段子集。 fields文档指定包含1的字段,如:fields: { <field1>: 1, <field2>: 1, ... }。见投影
从 MongoDB 3.6.14(和 3.4.23)开始,如果 fields 参数不是文档,则操作错误。
upsertboolean可选的。与update字段结合使用。
truefindAndModify()时:
如果没有文件匹配query,则创建一个新文档。有关详细信息,请参阅upsert 行为
更新与query匹配的单个文档。
要避免多次 upsert,请确保query字段为唯一索引
默认为false
bypassDocumentValidationboolean可选的。允许findAndModify在操作期间绕过文档验证。这使您可以更新不符合验证要求的文档。
version 3.2 中的新内容。
writeConcern文献可选的。表示写关注的文件。省略使用默认写入问题。
version 3.2 中的新内容。
maxTimeMS整数可选的。指定处理操作的 time 限制(以毫秒为单位)。
findAndModify用于运行命令的集合。
collation文献可选的。
指定要用于操作的整理
整理允许用户为 string 比较指定 language-specific 规则,例如字母和重音标记的规则。
排序规则选项具有以下语法:
排序规则:{
locale:<string>,
caseLevel:<boolean>,
caseFirst:<string>,
strength:<int>,
numericOrdering:<boolean>,
alternate:<string>,
maxVariable:<string>,
backwards :<boolean>
}
指定排序规则时,locale字段是必填字段;所有其他校对字段都是可选的。有关字段的说明,请参阅整理文件
如果未指定排序规则但集合具有默认排序规则(请参阅db.createCollection()),则操作将使用为集合指定的排序规则。
如果没有为集合或操作指定排序规则,MongoDB 使用先前版本中用于 string 比较的简单二进制比较。
您无法为操作指定多个排序规则。对于 example,您不能为每个字段指定不同的排序规则,或者如果使用排序执行查找,则不能对查找使用一个排序规则,而对排序使用另一个排序规则。
version 3.4 中的新内容。
arrayFiltersarray可选的。过滤器文档的 array,用于确定要在 array 字段上为更新操作修改哪些 array 元素。
在更新文档中,使用$ [<identifier>]过滤后的位置 operator 来定义标识符,然后在 array 过滤器文档中进行 reference。如果标识符未包含在更新文档中,则不能为标识符提供 array 过滤器文档。
注意
<identifier>必须以小写字母开头,并且只包含字母数字字符。
您可以在更新文档中多次包含相同的标识符;但是,对于更新文档中的每个不同标识符($[identifier]),您必须指定恰好一个对应的 array 过滤器文档。也就是说,您不能为同一标识符指定多个 array 过滤器文档。对于 example,如果 update 语句包含标识符x(可能多次),则不能为arrayFilters指定以下内容,其中包含 2 个单独的x过滤器文档:
[138]
但是,您可以在同一标识符上指定复合条件单个过滤器文档,例如以下示例:
[
{$or:[142]}
]
[
{$and:[146]}
]
[149]
例如,请参阅为 Array Update Operations 指定 arrayFilters
version 3.6 中的新内容。

产量

findAndModify命令返回包含以下字段的文档:

领域类型描述
value文献包含命令的返回 value。有关详细信息,请参阅
lastErrorObject文献包含有关更新文档的信息。有关详细信息,请参阅lastErrorObject
ok包含命令的执行状态。成功时为1,如果发生错误则为0

lastErrorObject

lastErrorObject嵌入文档包含以下字段:

领域类型描述
updatedExistingboolean如果update操作修改了现有文档,则包含true
upserted文献如果带有upsert: trueupdate操作导致新文档,则包含插入文档的ObjectId

对于remove操作,如果查询与文档匹配,则value包含已删除的文档。如果查询没有匹配要删除的文档,则value包含null

对于update操作,value嵌入文档包含以下内容:

  • 如果未设置new参数或false

  • 如果查询与文档匹配,则为 pre-modification 文档;

  • 否则,null

  • 如果newtrue

  • 修改后的文档,如果查询返回 match;

  • 插入的文档,如果upsert: true,没有文档与查询匹配;

  • 否则,null

更改 version 3.0:在以前的版本中,如果更新时,指定了sortupsert: true,并且未设置new选项或new: false,则findAndModify将在value字段中返回空文档{}而不是null

行为

Upsert 和 Unique Index

findAndModify命令包含upsert: true选项并且查询 field(s)没有唯一索引时,该命令可以在某些情况下多次插入文档。

考虑一个 example,其中不存在 name Andy的文档,并且多个 clients 发出以下命令:

db.runCommand(
   {
     findAndModify: "people",
     query: { name: "Andy" },
     sort: { rating: 1 },
     update: { $inc: { score: 1 } },
     upsert: true
   }
 )

如果所有命令在任何命令启动modify阶段之前完成query阶段,name字段上没有唯一索引,则命令可以各自执行 upsert,创建多个重复文档。

要防止创建多个重复文档,请在name字段上创建独特的指数。使用唯一索引,多个findAndModify命令将显示以下行为之一:

  • 正好一个findAndModify成功插入一个新文档。

  • 零个或多个findAndModify命令更新新插入的文档。

  • 零个或多个findAndModify命令在尝试插入副本时失败。如果命令由于唯一索引约束违规而失败,则可以重试该命令。如果没有删除文档,则重试不应失败。

Sharded Collections

分片环境中使用findAndModify时,query必须包含针对 shard cluster 的所有操作的碎片 keyfindAndModify针对 non-sharded 个实例的mongos实例发出的操作正常。

文件验证

findAndModify命令添加了对bypassDocumentValidation选项的支持,该选项允许您在使用验证规则插入或更新集合中的文档时绕过文件验证

与更新方法进行比较

更新文档时,findAndModifyupdate()方法的操作方式不同:

  • 默认情况下,两个操作都会修改单个文档。但是,带有multi选项的update()方法可以修改多个文档。

  • 如果多个文档匹配更新条件,对于findAndModify,您可以指定sort以提供对要更新的文档的某种控制措施。

使用update()方法的默认行为,您无法在多个文档 match 时指定要更新的单个文档。

  • 默认情况下,findAndModify返回包含文档的 pre-modified version 的 object,以及操作的状态。要获取更新的文档,请使用new选项。

update()方法返回包含操作状态的写结果 object。要 return 更新的文档,请使用find()方法。但是,其他更新可能已在您的更新和文档检索之间修改了文档。此外,如果更新仅修改了单个文档但匹配了多个文档,则需要使用其他逻辑来标识更新的文档。

修改单个文档时,findAndModifyupdate()方法都会自动更新文档。有关这些方法的操作的交互和顺序的更多详细信息,请参阅原子性和 Transactions

例子

更新和 Return

以下命令更新people集合中文档与query条件匹配的现有文档:

db.runCommand(
   {
     findAndModify: "people",
     query: { name: "Tom", state: "active", rating: { $gt: 10 } },
     sort: { rating: 1 },
     update: { $inc: { score: 1 } }
   }
)

此命令执行以下操作:

  • querypeople集合中查找name字段具有 value Tomstate字段具有 value activerating字段具有 value greater than 10 的文档。

  • sort以升序 order 命令查询结果。如果多个文档符合query条件,则命令将选择修改此sort所订购的第一个文档。

  • update increments score字段的 value 为 1。

  • 该命令返回包含以下字段的文档:

  • lastErrorObject字段包含命令的详细信息,包括true字段true

  • value字段包含为此更新选择的原始(i.e .pre-modification)文档:

{
  "lastErrorObject" : {
     "connectionId" : 1,
     "updatedExisting" : true,
     "n" : 1,
     "syncMillis" : 0,
     "writtenTo" : null,
     "err" : null,
     "ok" : 1
  },
  value" : {
    "_id" : ObjectId("54f62d2885e4be1f982b9c9c"),
    "name" : "Tom",
    "state" : "active",
    "rating" : 100,
    "score" : 5
  },
  "ok" : 1
}

要在value字段中 return 修改的文档,请在命令中添加new:true选项。

如果没有文档匹配query条件,则该命令将返回value字段中包含null的文档:

{ "value" : null, "ok" : 1 }

mongo shell 和许多司机提供findAndModify()辅助方法。使用 shell 帮助程序,此前一个操作可以采用以下形式:

db.people.findAndModify( {
   query: { name: "Tom", state: "active", rating: { $gt: 10 } },
   sort: { rating: 1 },
   update: { $inc: { score: 1 } }
} );

但是,findAndModify() shell 帮助器方法仅返回未修改的文档,或者如果newtrue,则返回已修改的文档。

{
   "_id" : ObjectId("54f62d2885e4be1f982b9c9c"),
   "name" : "Tom",
   "state" : "active",
   "rating" : 100,
   "score" : 5
}

upsert:true

以下findAndModify命令包含update操作的upsert: true选项,用于更新匹配的文档;如果不存在匹配的文档,则创建新文档:

db.runCommand(
               {
                 findAndModify: "people",
                 query: { name: "Gus", state: "active", rating: 100 },
                 sort: { rating: 1 },
                 update: { $inc: { score: 1 } },
                 upsert: true
               }
             )

如果命令找到匹配的文档,则该命令将执行更新。

如果命令找到匹配的文档,update with upsert:true操作将导致插入并返回包含以下字段的文档:

  • 包含命令详细信息的lastErrorObject字段,包括包含新插入文档的_id value 的字段upserted,以及

  • 包含nullvalue字段。

{
  "value" : null,
  "lastErrorObject" : {
     "updatedExisting" : false,
     "n" : 1,
     "upserted" : ObjectId("54f62c8bc85d4472eadea26f")
  },
  "ok" : 1
}

返回新文档

以下findAndModify命令包括upsert: true选项和new:true选项。该命令要么更新匹配的文档并返回更新的文档,要么如果不存在匹配的文档,则插入文档并在value字段中返回新插入的文档。

在以下 example 中,people集合中的任何文档都不匹配query条件:

db.runCommand(
   {
     findAndModify: "people",
     query: { name: "Pascal", state: "active", rating: 25 },
     sort: { rating: 1 },
     update: { $inc: { score: 1 } },
     upsert: true,
     new: true
   }
)

该命令返回value字段中新插入的文档:

{
  "lastErrorObject" : {
     "connectionId" : 1,
     "updatedExisting" : false,
     "upserted" : ObjectId("54f62bbfc85d4472eadea26d"),
     "n" : 1,
     "syncMillis" : 0,
     "writtenTo" : null,
     "err" : null,
     "ok" : 1
  },
  "value" : {
     "_id" : ObjectId("54f62bbfc85d4472eadea26d"),
     "name" : "Pascal",
     "rating" : 25,
     "state" : "active",
     "score" : 1
  },
  "ok" : 1
}

排序和删除

通过在rating字段上包含sort规范,以下 example 将从people集合中删除state value 为active且匹配文档中最低rating的单个文档:

db.runCommand(
   {
     findAndModify: "people",
     query: { state: "active" },
     sort: { rating: 1 },
     remove: true
   }
)

该命令返回已删除的文档:

{
  "lastErrorObject" : {
     "connectionId" : 1,
     "n" : 1,
     "syncMillis" : 0,
     "writtenTo" : null,
     "err" : null,
     "ok" : 1
  },
  "value" : {
     "_id" : ObjectId("54f62a6785e4be1f982b9c9b"),
     "name" : "XYZ123",
     "score" : 1,
     "state" : "active",
     "rating" : 3
  },
  "ok" : 1
}

指定排序规则

version 3.4 中的新内容。

整理允许用户为 string 比较指定 language-specific 规则,例如字母和重音标记的规则。

集合myColl具有以下文档:

{ _id: 1, category: "café", status: "A" }
{ _id: 2, category: "cafe", status: "a" }
{ _id: 3, category: "cafE", status: "a" }

以下操作包括整理选项:

db.runCommand(
   {
     findAndModify: "myColl",
     query: { category: "cafe", status: "a" },
     sort: { category: 1 },
     update: { $set: { status: "Updated" } },
     collation: { locale: "fr", strength: 1 }
   }
)

该操作返回以下文档:

{
   "lastErrorObject" : {
      "updatedExisting" : true,
      "n" : 1
   },
   "value" : {
      "_id" : 1,
      "category" : "café",
      "status" : "A"
   },
   "ok" : 1
}

为 Array Update Operations 指定 arrayFilters

version 3.6 中的新内容。

从 MongoDB 3.6 开始,在更新 array 字段时,您可以指定arrayFilters来确定要更新的 array 元素。

更新元素 Match arrayFilters Criteria

使用以下文档创建集合students

db.students.insert([
   { "_id" : 1, "grades" : [ 95, 92, 90 ] },
   { "_id" : 2, "grades" : [ 98, 100, 102 ] },
   { "_id" : 3, "grades" : [ 95, 110, 100 ] }
])

要修改grades array 中大于或等于100的所有元素,请使用位置$ [<identifier>]operator 和arrayFilters选项:

db.runCommand(
   {
     findAndModify: "students",
     query: { grades: { $gte: 100 } },
     update:  { $set: { "grades.$[element]" : 100 } },
     arrayFilters: [ { "element": { $gte: 100 } } ]
   }
)

该操作更新单个文档的grades字段,在操作之后,该集合具有以下文档:

{ "_id" : 1, "grades" : [ 95, 92, 90 ] }
{ "_id" : 2, "grades" : [ 98, 100, 100 ] }
{ "_id" : 3, "grades" : [ 95, 110, 100 ] }

更新 Array 文档的特定元素

使用以下文档创建集合students2

db.students2.insert([
   {
      "_id" : 1,
      "grades" : [
         { "grade" : 80, "mean" : 75, "std" : 6 },
         { "grade" : 85, "mean" : 90, "std" : 4 },
         { "grade" : 85, "mean" : 85, "std" : 6 }
      ]
   },
   {
      "_id" : 2,
      "grades" : [
         { "grade" : 90, "mean" : 75, "std" : 6 },
         { "grade" : 87, "mean" : 90, "std" : 3 },
         { "grade" : 85, "mean" : 85, "std" : 4 }
      ]
   }
])

要修改grades array 中等级大于或等于85的所有元素的mean字段的 value,请将位置$ [<identifier>]operator 与arrayFilters一起使用:

db.runCommand(
   {
     findAndModify: "students2",
     query: { },
     update: { $set: { "grades.$[elem].mean" : 100 } },
     arrayFilters: [ { "elem.grade": { $gte: 85 } } ]
   }
)

该操作更新单个文档的grades字段,在操作之后,该集合具有以下文档:

{
   "_id" : 1,
   "grades" : [
      { "grade" : 80, "mean" : 75, "std" : 6 },
      { "grade" : 85, "mean" : 100, "std" : 4 },
      { "grade" : 85, "mean" : 100, "std" : 6 }
    ]
}
{
   "_id" : 2,
   "grades" : [
      { "grade" : 90, "mean" : 75, "std" : 6 },
      { "grade" : 87, "mean" : 90, "std" : 3 },
      { "grade" : 85, "mean" : 85, "std" : 4 }
   ]
}

也可以看看 可线性化通过 findAndModify 读取