$currentDate

$ currentDate运算符将字段的值设置为当前日期,可以是Date或时间戳。默认类型为日期。

$currentDate的形式为:

1
{ $currentDate: { <field1>: <typeSpecification1>, ... } }

可以是:

  • 一个布尔值,true用于将字段值设置为当前日期作为Date,或者
  • 明确指定类型的文档{$type:“ timestamp”}{$type:“ date”}。运算符区分大小写,并且仅接受小写的“时间戳”或小写的“日期”。

若要在嵌入式文档或数组中指定<field>,请使用点表示法。

特性

如果该字段不存在,则$currentDate将该字段添加到文档中。

例子

customers使用以下文档创建样本集合:

1
2
3
db.customers.insertOne(
   { _id: 1, status: "a", lastModified: ISODate("2013-10-02T01:11:18.965Z") }
)

以下操作将lastModified字段更新为当前日期,将“cancellation.date”字段更新为当前时间戳,并将状态字段更新为“D”,将“cancellation.reason”更新为“用户请求”。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
db.customers.updateOne(
   { _id: 1 },
   {
     $currentDate: {
        lastModified: true,
        "cancellation.date": { $type: "timestamp" }
     },
     $set: {
        "cancellation.reason": "user request",
        status: "D"
     }
   }
)

更新后的文档类似于:

1
2
3
4
5
6
7
8
9
{
   "_id" : 1,
   "status" : "D",
   "lastModified" : ISODate("2020-01-22T21:21:41.052Z"),
   "cancellation" : {
      "date" : Timestamp(1579728101, 1),
      "reason" : "user request"
   }
}

Aggregation替代$currentDate

从4.2版开始,更新方法可以接受聚合管道。这样,可以使用聚合阶段$set和聚合变量 NOW(对于当前日期时间)和CLUSTER_TIME (对于当前时间戳记)将前面的示例重写为以下示例:

TIP:

  • 要访问聚合变量,请在变量前加双美元符号$$并用引号引起来。
  • CLUSTER_TIME 仅在副本集和分片群集上可用。
  • 在整个管道中,NOW和CLUSTER_TIME值保持不变。
1
2
3
4
5
6
db.customers.updateOne(
  { _id: 1 },
  [
   { $set: { lastModified: "$$NOW", cancellation: {date: "$$CLUSTER_TIME", reason: "user request"}, status: "D" } }
  ]
)

查询应返回以下文档:

1
2
3
4
5
6
7
8
9
{
   "_id" : 1,
   "status" : "D",
   "lastModified" : ISODate("2020-01-22T21:02:18.994Z"),
   "cancellation" : {
      "date" : Timestamp(1579726934, 2),
      "reason" : "user request"
   }
}

$inc

$inc通过增加指定的值的字段,并具有以下形式:

1
{ $inc: { <field1>: <amount1>, <field2>: <amount2>, ... } }

若要在嵌入式文档或数组中指定,请使用点表示法。

特性

$inc运算符接受正值和负值。

如果该字段不存在,则$inc将创建该字段并将该字段设置为指定的值。

在具有空值的字段上使用$inc运算符将产生错误。

$inc是单个文档中的原子操作。

例子

考虑products包含以下文档的集合:

1
2
3
4
5
6
7
8
9
{
  _id: 1,
  sku: "abc123",
  quantity: 10,
  metrics: {
    orders: 2,
    ratings: 3.5
  }
}

以下update()操作使用$inc运算符将quantity字段减小2(即增加-2),并将"metrics.orders"字段增大1:

1
2
3
4
db.products.update(
   { sku: "abc123" },
   { $inc: { quantity: -2, "metrics.orders": 1 } }
)

更新后的文档类似于:

1
2
3
4
5
6
7
8
9
{
   "_id" : 1,
   "sku" : "abc123",
   "quantity" : 8,
   "metrics" : {
      "orders" : 3,
      "ratings" : 3.5
   }
}

$min

如果指定的值小于字段的当前值,则$min将字段的值更新为指定的值。 $min运算符可以使用BSON比较顺序来比较不同类型的值。

1
{ $min: { <field1>: <value1>, ... } }

若要在嵌入式文档或数组中指定<field>,请使用点表示法。

特性

如果该字段不存在,则$min运算符会将字段设置为指定的值。

对于不同类型的值(例如数字和空值)之间的比较,$min使用BSON比较顺序

例子

使用$min比较数字

考虑集合中的以下文档scores:

1
{ _id: 1, highScore: 800, lowScore: 200 }

文档的lowScore当前具有值200。以下操作使用$ min将200与指定值150进行比较,由于150小于200,因此将lowScore的值更新为150:

1
db.scores.update( { _id: 1 }, { $min: { lowScore: 150 } } )

scores现在,该集合包含以下修改后的文档:

1
{ _id: 1, highScore: 800, lowScore: 150 }

下一操作无效,因为该字段的当前值(lowScore即150)小于250:

1
db.scores.update( { _id: 1 }, { $min: { lowScore: 250 } } )

该文档在scores集合中保持不变:

1
{ _id: 1, highScore: 800, lowScore: 150 }

使用$min比较日期

考虑集合中的以下文档tags:

1
2
3
4
5
6
{
  _id: 1,
  desc: "crafts",
  dateEntered: ISODate("2013-10-01T05:00:00Z"),
  dateExpired: ISODate("2013-10-01T16:38:16Z")
}

以下操作将dateEntered字段的当前值(即ISODate(“ 2013-10-01T05:00:00Z”))与指定的日期new Date(“ 2013-09-25”)进行比较,以确定是否更新该字段:

1
2
3
4
db.tags.update(
   { _id: 1 },
   { $min: { dateEntered: new Date("2013-09-25") } }
)

该操作将更新dateEntered字段:

1
2
3
4
5
6
7
8
{
  _id: 1,
  desc: "crafts",

  dateEntered: ISODate("2013-09-25T00:00:00Z"),

  dateExpired: ISODate("2013-10-01T16:38:16Z")
}

$max

如果指定的值大于字段的当前值,则$ max运算符会将字段的值更新为指定的值。 $ max运算符可以使用BSON比较顺序来比较不同类型的值。

$max运算符表达式的形式为:

1
{ $max: { <field1>: <value1>, ... } }

若要在嵌入式文档或数组中指定<field>,请使用点表示法。

特性

如果该字段不存在,则$max操作员将该字段设置为指定值。

例子

使用$max比较数字

考虑集合中的以下文档scores:

1
{ _id: 1, highScore: 800, lowScore: 200 }

文档的highScore当前具有值800。以下操作使用$ max将800与指定值950进行比较,由于950大于800,因此将highScore的值更新为950。

1
db.scores.update( { _id: 1 }, { $max: { highScore: 950 } } )

scores现在,该集合包含以下修改后的文档:

1
{ _id: 1, highScore: 950, lowScore: 200 }

下一操作无效,因为该字段的当前值(highScore即950)大于870:

1
db.scores.update( { _id: 1 }, { $max: { highScore: 870 } } )

该文档在scores集合中保持不变:

1
{ _id: 1, highScore: 950, lowScore: 200 }

使用$max比较日期

考虑集合中的以下文档tags:

1
2
3
4
5
6
{
  _id: 1,
  desc: "crafts",
  dateEntered: ISODate("2013-10-01T05:00:00Z"),
  dateExpired: ISODate("2013-10-01T16:38:16.163Z")
}

以下操作将dateExpired字段的当前值(即ISODate(“ 2013-10-01T16:38:16.163Z”))与指定的日期new Date(“ 2013-09-30”)进行比较,以确定是否更新field:

1
2
3
4
db.tags.update(
   { _id: 1 },
   { $max: { dateExpired: new Date("2013-09-30") } }
)

操作并没有更新的dateExpired领域:

1
2
3
4
5
6
7
8
{
   _id: 1,
   desc: "decorative arts",
   dateEntered: ISODate("2013-10-01T05:00:00Z"),

   dateExpired: ISODate("2013-10-01T16:38:16.163Z")

}

$mul

将字段的值乘以数字。要指定 $mul表达式,请使用以下原型:

1
{ $mul: { <field1>: <number1>, ... } }

要更新的字段必须包含一个数字值。

若要在嵌入式文档或数组中指定<field>,请使用点表示法。

特性

缺少字段

如果文档中不存在该字段,则$ mul将创建该字段并将其值设置为与乘法器相同的数字类型为零。

原子

$mul 是单个文档中的原子操作。

混合型

与混合数字类型(32位整数,64位整数,浮点数)的值相乘可能会导致数字类型转换。对于与混合数值类型的值相乘,将应用以下类型转换规则:

注意

  • 如果两个32位整数的乘积超过了32位整数的最大值,则结果为64位整数。
  • 超过64位整数最大值的任何类型的整数运算都会产生错误。

例子

乘以字段的值

考虑products包含以下文档的集合:

1
{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("10.99"), "qty" : 25 }

以下db.collection.update()操作使用$mul运算符将price by 1.25和qty字段乘以2:

1
2
3
4
db.products.update(
   { _id: 1 },
   { $mul: { price: NumberDecimal("1.25"), qty: 2 } }
)

该操作得出以下文档,其中价格的新值反映了原始值10.99乘以1.25,而数量的新值反映了原始值25乘以2:

1
{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("13.7375"), "qty" : 50 }

应用$mul操作员到一个不存在的字段

考虑products包含以下文档的集合:

1
{ _id: 2,  item: "Unknown" }

以下db.collection.update()操作将$mul运算符应用于文档中不存在的字段价格来更新文档:

1
2
3
4
db.products.update(
   { _id: 2 },
   { $mul: { price: NumberLong(100) } }
)

该操作将导致以下文档的price字段设置为数值类型NumberLong的值0 ,该类型与乘数相同:

1
{ "_id" : 2, "item" : "Unknown", "price" : NumberLong(0) }

乘法混合数值类型

考虑products包含以下文档的集合:

1
{ _id: 3,  item: "XYZ", price: NumberLong(10) }

以下db.collection.update()操作使用$ mul运算符将价格字段NumberLong(10)中的值乘以NumberInt(5)

1
2
3
4
db.products.update(
   { _id: 3 },
   { $mul: { price: NumberInt(5) } }
)

该操作产生以下文档:

1
{ "_id" : 3, "item" : "XYZ", "price" : NumberLong(50) }

该price字段中的值是NumberLong类型。

$rename

$rename运算符将更新字段名称,并具有以下格式

1
{$rename: { <field1>: <newName1>, <field2>: <newName2>, ... } }

新的字段名称必须与现有的字段名称不同。要在嵌入式文档中指定<field>,请使用点号。

考虑以下示例:

1
db.students.update( { _id: 1 }, { $rename: { 'nickname': 'alias', 'cell': 'mobile' } } )

此操作将字段重命名nickname为alias,并将字段重命名cell为mobile。

特性

$rename运算符在逻辑上执行旧名称和新名称的$unset,然后使用新名称执行$set操作。因此,该操作可能不会保留文档中字段的顺序;即重命名的字段可能会在文档中移动。

如果文档中已有一个带有<newName>的字段,则$rename运算符将删除该字段,并将指定的<field>重命名为<newName>

如果文档中不存在要重命名的字段,则$rename不执行任何操作(即不执行任何操作)。

对于嵌入式文档中的字段,$rename运算符可以重命名这些字段,也可以将字段移入或移出嵌入式文档。如果这些字段在数组元素中,则$rename不起作用。

例子

集合students包含以下文档,其中某个字段的nmae拼写错误,即应为name:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
{
  "_id": 1,
  "alias": [ "The American Cincinnatus", "The American Fabius" ],
  "mobile": "555-555-5555",
  "nmae": { "first" : "george", "last" : "washington" }
}

{
  "_id": 2,
  "alias": [ "My dearest friend" ],
  "mobile": "222-222-2222",
  "nmae": { "first" : "abigail", "last" : "adams" }
}

{
  "_id": 3,
  "alias": [ "Amazing grace" ],
  "mobile": "111-111-1111",
  "nmae": { "first" : "grace", "last" : "hopper" }
}

本节中的示例将依次更新集合中的文档。

重命名字段

要重命名字段,请使用字段$rename的当前名称和新名称来调用运算符:

1
db.students.updateMany( {}, { $rename: { "nmae": "name" } } )

此操作将重命名字段nmae来name为集合中的所有文档:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{
  "_id": 1,
  "alias": [ "The American Cincinnatus", "The American Fabius" ],
  "mobile": "555-555-5555",
  "name": { "first" : "george", "last" : "washington" }
}

{
   "_id" : 2,
   "alias" : [ "My dearest friend" ],
   "mobile" : "222-222-2222",
   "name" : { "first" : "abigail", "last" : "adams" }
}

{ "_id" : 3,
  "alias" : [ "Amazing grace" ],
  "mobile" : "111-111-1111",
  "name" : { "first" : "grace", "last" : "hopper" } }

重命名嵌入文档中的字段

要重命名嵌入式文档中的字段,请使用点表示法调用$rename运算符以引用该字段。如果该字段将保留在同一嵌入式文档中,则还应使用新名称中的点号,如下所示:

1
db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )

此操作将嵌入式字段重命名first为fname:

1
2
3
4
5
6
{
  "_id" : 1,
  "alias" : [ "The American Cincinnatus", "The American Fabius" ],
  "mobile" : "555-555-5555",
  "name" : { "fname" : "george", "last" : "washington" }
}

重命名一个不存在的字段

重命名字段并且现有字段名称引用的字段不存在时,$rename运算符不执行任何操作,如下所示:

1
db.students.update( { _id: 1 }, { $rename: { 'wife': 'spouse' } } )

此操作没有执行任何操作,因为没有名为wife的字段。

$set

$set操作者更换一个字段与指定的值。

所述$set操作者的表达具有以下形式:

1
{ $set: { <field1>: <value1>, ... } }

若要在嵌入式文档或数组中指定<field>,请使用点表示法。

特性

如果该字段不存在,$set则将添加具有指定值的新字段,前提是该新字段不违反类型约束。如果为不存在的字段指定点划线路径,$ set将根据需要创建嵌入的文档,以实现到该字段的点划线路径。

如果指定多个字段/值对,$set将更新或创建每个字段。

例子

考虑products包含以下文档的集合:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  _id: 100,
  sku: "abc123",
  quantity: 250,
  instock: true,
  reorder: false,
  details: { model: "14Q2", make: "xyz" },
  tags: [ "apparel", "clothing" ],
  ratings: [ { by: "ijk", rating: 4 } ]
}

设置顶级字段

对于符合_id等于的条件的文档100,以下操作使用$set运算符更新quantity字段,details字段和tags 字段的值。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
db.products.update(
   { _id: 100 },
   { $set:
      {
        quantity: 500,
        details: { model: "14Q3", make: "xyz" },
        tags: [ "coats", "outerwear", "clothing" ]
      }
   }
)

该操作将值替换为:quantity为500。详细信息字段到新的嵌入式文档,而标签字段到新数组。

在嵌入式文档中设置字段

若要在嵌入式文档或数组中指定<field>,请使用点表示法。

对于符合标准_id等于100的文档,以下操作将更新details文档中的make字段:

1
2
3
4
db.products.update(
   { _id: 100 },
   { $set: { "details.make": "zzz" } }
)

在数组中设置元素

若要在嵌入式文档或数组中指定<field>,请使用点表示法。

对于符合等于_id等于100的条件的文档,以下操作将更新tags数组的第二个元素(数组索引为1)的值,以及ratings数组的第一个元素(array索引为0)中的rating字段。

1
2
3
4
5
6
7
8
9
db.products.update(
   { _id: 100 },
   { $set:
      {
        "tags.1": "rain gear",
        "ratings.0.rating": 2
      }
   }
)

$setOnInsert

如果使用upsert:true进行更新操作会导致插入文档,则$setOnInsertm’k会将指定的值分配给文档中的字段。如果更新操作未导致插入,则$setOnInsert不执行任何操作。

您可以为db.collection.update()db.collection.findAndModify()方法指定upsert选项。

1
2
3
4
5
db.collection.update(
   <query>,
   { $setOnInsert: { <field1>: <value1>, ... } },
   { upsert: true }
)

若要在嵌入式文档或数组中指定<field>,请使用点表示法。

例子

名为的集合products不包含任何文档。

然后,以下带有upsert:true的db.collection.update()插入新文档。

1
2
3
4
5
6
7
8
db.products.update(
  { _id: 1 },
  {
     $set: { item: "apple" },
     $setOnInsert: { defaultQty: 100 }
  },
  { upsert: true }
)

MongoDB从<query>条件创建一个_id等于1的新文档,然后将$set$setOnInsert操作应用于此文档。

该products集合包含新插入的文档:

1
{ "_id" : 1, "item" : "apple", "defaultQty" : 100 }

如果具有upsert:true的db.collection.update()找到了匹配的文档,则MongoDB将执行更新,应用$set操作,但忽略$setOnInsert操作。

$unset

$unset操作删除特定的领域。请考虑以下语法:

1
{ $unset: { <field1>: "", ... } }

$unset表达式中的指定值(即“”)不会影响该操作。

若要在嵌入式文档或数组中指定<field>,请使用点表示法。

特性

如果该字段不存在,则$unset不执行任何操作(即不执行任何操作)。

$配合使用以匹配数组元素时,$unset会将匹配元素替换为null,而不是从数组中删除匹配元素。此特性使数组大小和元素位置保持一致。

例子

以下update()操作使用$unset运算符从字段sku值为未知的产品集合中的第一个文档中删除字段quantity和instock。

1
2
3
4
db.products.update(
   { sku: "unknown" },
   { $unset: { quantity: "", instock: "" } }
)