$

$运算符标识要更新的数组中的元素,而无需显式指定数组中元素的位置。

消歧

  • 要通过读取操作$投影或返回数组元素,请参阅投影运算符。
  • 要更新数组中的所有元素,请参阅all位置运算符 $[]
  • 要更新所有符合一个或多个数组过滤条件的元素,请参阅过滤后的位置运算符 $[<identifier>]

$运算符的格式为:

1
{ "<array>.$" : value }

与更新操作(例如 db.collection.update()和 db.collection.findAndModify())一起使用时

  • 位置$运算符充当与查询文档匹配的第一个元素的占位符
  • 数组字段必须作为查询文档的一部分出现。

例如:

1
2
3
4
db.collection.update(
   { <array>: value ... },
   { <update operator>: { "<array>.$" : value } }
)

特性

upsert

不要将位置运算符$upsert操作一起使用,因为插入操作会将$用作插入文档中的字段名称。

嵌套数组

位置$运算符不能用于遍历一个以上数组的查询,例如遍历嵌套在其他数组中的数组的查询,因为$占位符的替换是单个值

Unsets

$unset运算符一起使用时,位置$运算符不会从数组中删除匹配的元素,而是将其设置为null。

否定

如果查询使用否定运算符,如$ne$not或者$nin,那么您将无法使用位置运算符来更新此数组中的值。

但是,如果查询的否定部分在$elemMatch表达式内,则可以使用位置运算符更新此字段。

例子

数组中的更新值

students使用以下文档创建一个集合:

1
2
3
4
5
db.students.insert([
   { "_id" : 1, "grades" : [ 85, 80, 80 ] },
   { "_id" : 2, "grades" : [ 88, 90, 92 ] },
   { "_id" : 3, "grades" : [ 85, 100, 90 ] }
])

要更新grades数组中第一个值为80到82的元素,如果您不知道该元素在数组中的位置,请使用$运算符:

重要:您必须将数组字段包含在query文档中。

1
2
3
4
db.students.updateOne(
   { _id: 1, grades: 80 },
   { $set: { "grades.$" : 82 } }
)

位置$运算符充当更新查询文档的第一个匹配项的占位符 。

操作后,students集合包含以下文档:

1
2
3
{ "_id" : 1, "grades" : [ 85, 82, 80 ] }
{ "_id" : 2, "grades" : [ 88, 90, 92 ] }
{ "_id" : 3, "grades" : [ 85, 100, 90 ] }

更新数组中的文档

位置$运算符有助于更新包含嵌入式文档的数组。使用位置$运算符可使用$运算符上的点符号访问嵌入文档中的字段。

1
2
3
4
db.collection.update(
   { <query selector> },
   { <update operator>: { "array.$.field" : value } }
)

请考虑students集合中的以下文档,该文档的 grades元素值为嵌入式文档的数组:

1
2
3
4
5
6
7
8
{
  _id: 4,
  grades: [
     { grade: 80, mean: 75, std: 8 },
     { grade: 85, mean: 90, std: 5 },
     { grade: 85, mean: 85, std: 8 }
  ]
}

使用位置$运算符更新std匹配grade等于85条件的第一个数组元素的字段:

重要

您必须将数组字段包含在query文档中。

1
2
3
4
db.students.updateOne(
   { _id: 4, "grades.grade": 85 },
   { $set: { "grades.$.std" : 6 } }
)

操作后,文档具有以下更新值:

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

使用多个字段匹配更新嵌入式文档

$运算符可以更新与$elemMatch()运算符指定的多个查询条件匹配的第一个数组元素。

考虑students集合中的以下文档,该文档的grades字段值为嵌入式文档的数组:

1
2
3
4
5
6
7
8
{
  _id: 5,
  grades: [
     { grade: 80, mean: 75, std: 8 },
     { grade: 85, mean: 90, std: 5 },
     { grade: 90, mean: 85, std: 3 }
  ]
}

在下面的示例中,$运算符更新第一个嵌入式文档中std字段的值,该字段的等级字段的值小于或等于90,而平均值字段的值大于80:

1
2
3
4
5
6
7
db.students.updateOne(
   {
     _id: 5,
     grades: { $elemMatch: { grade: { $lte: 90 }, mean: { $gt: 80 } } }
   },
   { $set: { "grades.$.std" : 6 } }
)

此操作将更新符合条件的第一个嵌入式文档,即数组中的第二个嵌入式文档:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  _id: 5,
  grades: [
    { grade: 80, mean: 75, std: 8 },

    { grade: 85, mean: 90, std: 6 },

    { grade: 90, mean: 85, std: 3 }
  ]
}

$[]

3.6版的新功能。

all位置运算符$[]指示update运算符应修改指定数组字段中的所有元素。

$[]具有下列形式:

1
{ <update operator>: { "<array>.$[]" : value } }

用于更新操作(例如db.collection.update()和 db.collection.findAndModify())来修改一个或多个查询条件匹配的文档的所有数组元素。例如:

1
2
3
4
db.collection.updateMany(
   { <query conditions> },
   { <update operator>: { "<array>.$[]" : value } }
)

特性

upsert

如果upsert操作导致插入,则query必须在array字段上包含完全相等的匹配项,以便$[]在update语句中使用位置运算符。

例如,$[]在更新文档中使用的以下upsert操作在array字段上指定完全相等的匹配条件:

1
2
3
4
5
db.collection.update(
   { myArray: [ 5, 8 ] },
   { $set: { "myArray.$[]": 10 } },
   { upsert: true }
)

如果不存在此类文档,则该操作将导致插入以下文档:

1
{ "_id" : ObjectId(...), "myArray" : [ 10, 10 ] }

如果upsert操作不包括完全相等的匹配项,并且找不到匹配的文档要更新,则upsert操作将出错。

例如,如果找不到匹配的文档来更新,则以下操作将出错:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
db.collection.update(
   { myArray: 5 },
   { $set: { "myArray.$[]": 10 } },
   { upsert: true }
)

db.collection.update(
   { },
   { $set: { "myArray.$[]": 10 } },
   { upsert: true }
)

嵌套数组

$[]运算符可用于遍历多个数组和嵌套数组的查询。

例子

更新数组中的所有元素

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

1
2
3
{ "_id" : 1, "grades" : [ 85, 82, 80 ] }
{ "_id" : 2, "grades" : [ 88, 90, 92 ] }
{ "_id" : 3, "grades" : [ 85, 100, 90 ] }

要为集合中的所有文档增加grades数组中的所有元素10,请使用$[]运算符:

1
2
3
4
5
db.students.update(
   { },
   { $inc: { "grades.$[]": 10 } },
   { multi: true }
)

所有位置的$[]运算符都充当array字段中所有元素的占位符。

操作后,students集合包含以下文档:

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

更新数组中的所有文档

$[]操作方便的更新包含嵌入文档数组。要访问嵌入文档中的字段,请在运算符$[]上使用点符号。

1
2
3
4
db.collection.update(
   { <query selector> },
   { <update operator>: { "array.$[].field" : value } }
)

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
   "_id" : 1,
   "grades" : [
      { "grade" : 80, "mean" : 75, "std" : 8 },
      { "grade" : 85, "mean" : 90, "std" : 6 },
      { "grade" : 85, "mean" : 85, "std" : 8 }
   ]
}
{
   "_id" : 2,
   "grades" : [
      { "grade" : 90, "mean" : 75, "std" : 8 },
      { "grade" : 87, "mean" : 90, "std" : 5 },
      { "grade" : 85, "mean" : 85, "std" : 6 }
   ]
}

要为grades数组中的所有元素修改std字段的值,请使用位置$[]运算符:

1
2
3
4
5
db.students2.update(
   { },
   { $inc: { "grades.$[].std" : -2 } },
   { multi: true }
)

操作后,集合具有以下文档:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
   "_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 }
   ]
}

使用否定查询运算符更新指定的数组

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

1
2
3
{ "_id" : 1, "grades" : [ 85, 82, 80 ] }
{ "_id" : 2, "grades" : [ 88, 90, 92 ] }
{ "_id" : 3, "grades" : [ 85, 100, 90 ] }

要使所有文档的等级数组中的所有元素增加10,等级数组中值为100的元素除外,请使用$[]运算符:

1
2
3
4
5
db.results.update(
   { "grades" : { $ne: 100 } },
   { $inc: { "grades.$[]": 10 } },
   { multi: true }
)

$[]运算符充当数组字段中所有元素的占位符。

操作后,students集合包含以下文档:

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

$[<identifier>]一起更新嵌套数组

$[]位置运算符与过滤器$[<identifier>]位置运算符一起可用于更新嵌套数组。

students3使用以下文档创建一个集合:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
db.students3.insert([
   { "_id" : 1,
      "grades" : [
        { type: "quiz", questions: [ 10, 8, 5 ] },
        { type: "quiz", questions: [ 8, 9, 6 ] },
        { type: "hw", questions: [ 5, 4, 3 ] },
        { type: "exam", questions: [ 25, 10, 23, 0 ] },
      ]
   }
])

要更新嵌套的grades.questions数组中所有大于或等于8的值,而不管类型如何:

1
2
3
4
5
db.students3.update(
   {},
   { $inc: { "grades.$[].questions.$[score]": 2 } },
   { arrayFilters: [  { "score": { $gte: 8 } } ], multi: true}
)

$[<identifier>]

3.6版的新功能。

过滤后的位置运算符$[<identifier>]标识与arrayFilters条件匹配的数组元素以进行更新操作,例如db.collection.update()和 db.collection.findAndModify()。

与该arrayFilters选项结合使用,$[<identifier>]运算符具有以下形式:

1
2
{ <update operator>: { "<array>.$[<identifier>]" : value } },
{ arrayFilters: [ { <identifier>: <condition> } ] }

与arrayFilters选项结合使用,以更新一个或多个与查询条件匹配的文档中所有与arrayFilters条件匹配的元素。例如:

1
2
3
4
5
db.collection.updateMany(
   { <query conditions> },
   { <update operator>: { "<array>.$[<identifier>]" : value } },
   { arrayFilters: [ { <identifier>: <condition> } ] }
)

注意

<identifier>必须以小写字母开头,并且只包含字母数字字符。

特性

upsert

如果upsert操作导致插入,则query必须在array字段上包含完全相等的匹配项才能在update语句中使用$[<identifier>]

例如,$[<identifier>]在更新文档中使用的以下upsert操作在array字段上指定完全相等的匹配条件:

1
2
3
4
5
6
db.collection.update(
   { myArray: [ 0, 1 ] },
   { $set: { "myArray.$[element]": 2 } },
   { arrayFilters: [ { element: 0 } ],
     upsert: true }
)

如果不存在这样的文档,则该操作将导致插入类似于以下内容的文档:

1
{ "_id" : ObjectId(...), "myArray" : [ 2, 1 ] }

如果upsert操作不包括完全相等的匹配项,并且找不到匹配的文档要更新,则upsert操作将出错。例如,如果找不到匹配的文档来更新,则以下操作将出错:

1
2
3
4
5
6
db.array.update(
   { },
   { $set: { "myArray.$[element]": 10 } },
   { arrayFilters: [ { element: 9 } ],
     upsert: true }
)

该操作将返回类似于以下内容的错误:

1
2
3
4
5
6
7
8
9
WriteResult({
   "nMatched" : 0,
   "nUpserted" : 0,
   "nModified" : 0,
   "writeError" : {
      "code" : 2,
      "errmsg" : "The path 'myArray' must exist in the document in order to apply array updates."
   }
})

嵌套数组

过滤后的位置运算符$[<identifier>]可用于遍历多个数组和嵌套数组的查询。

例子

更新所有匹配arrayFilters的数组元素

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

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

要更新grades数组中所有大于或等于100的元素,请对arrayFilters使用过滤后的位置运算符$[<identifier>]

1
2
3
4
5
6
7
db.students.update(
   { },
   { $set: { "grades.$[element]" : 100 } },
   { multi: true,
     arrayFilters: [ { "element": { $gte: 100 } } ]
   }
)

位置$[<identifier>]运算符充当数组字段中与arrayFilters中指定的条件匹配的所有元素的占位符。

操作后,students集合包含以下文档:

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

更新arrayFilters数组中所有匹配的文档

$[<identifier>]操作有利于更新包含嵌入文档数组。要访问嵌入文档中的字段,使用点符号上$[<identifier>]

1
2
3
4
5
db.collection.update(
   { <query selector> },
   { <update operator>: { "array.$[<identifier>].field" : value } },
   { arrayFilters: [ { <identifier>: <condition> } } ] }
)

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
   "_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中mean大于或等于85的grades数组中所有元素的字段,请使用位置$[<identifier>]运算符和arrayFilters

1
2
3
4
5
6
7
8
db.students2.update(
   { },
   { $set: { "grades.$[elem].mean" : 100 } },
   {
     multi: true,
     arrayFilters: [ { "elem.grade": { $gte: 85 } } ]
   }
)

操作后,集合具有以下文档:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
   "_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" : 100, "std" : 6 },
      { "grade" : 87, "mean" : 100, "std" : 3 },
      { "grade" : 85, "mean" : 100, "std" : 4 }
   ]
}

更新匹配多个条件的所有数组元素

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
   "_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" : 100, "std" : 6 },
      { "grade" : 87, "mean" : 100, "std" : 3 },
      { "grade" : 85, "mean" : 100, "std" : 4 }
   ]
}

若要修改成绩数组中所有成绩均大于或等于80且std大于或等于5的std字段的值,请使用位置$[<identifier>]运算符和arrayFilters

1
2
3
4
5
db.students2.update(
   { },
   { $inc: { "grades.$[elem].std" : -1 } },
   { arrayFilters: [ { "elem.grade": { $gte: 80 }, "elem.std": { $gt: 5 } } ], multi: true }
)

操作后,集合具有以下文档:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{  "_id" : 1,
   "grades" : [
      { "grade" : 80, "mean" : 75, "std" : 5 },
      { "grade" : 85, "mean" : 100, "std" : 4 },
      { "grade" : 85, "mean" : 100, "std" : 5 }
   ]
}
{
   "_id" : 2,
   "grades" : [
      { "grade" : 90, "mean" : 100, "std" : 5 },
      { "grade" : 87, "mean" : 100, "std" : 3 },
      { "grade" : 85, "mean" : 100, "std" : 4 }
   ]
}

使用求反运算符更新数组元素

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
   "_id": 1,
   "name": "Christine Franklin",
   "degrees": [
      { "level": "Master",
        "major": "Biology",
        "completion_year": 2010,
        "faculty": "Science"
      },
      {
        "level": "Bachelor",
        "major": "Biology",
        "completion_year": 2008,
        "faculty": "Science"
      }
   ],
   "school_email": "cfranklin@example.edu",
   "email": "christine@example.com"
}
{
   "_id": 2,
   "name": "Reyansh Sengupta",
   "degrees": [
      { "level": "Bachelor",
        "major": "Chemical Engineering",
        "completion_year": 2002,
        "faculty": "Engineering"
      }
   ],
   "school_email": "rsengupta2@example.edu"
}

若要修改度数组中不具有"level": "Bachelor"的所有元素,请对$ne查询运算符使用位置[<identifier>]操作

1
2
3
4
5
6
db.alumni.update(
   { },
   { $set : { "degrees.$[degree].gradcampaign" : 1 } },
   { arrayFilters : [ {"degree.level" : { $ne: "Bachelor" } } ],
     multi : true }
)

操作后,集合具有以下文档:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{
   "_id" : 1,
   "name" : "Christine Franklin",
   "degrees" : [
      {
         "level" : "Master",
         "major" : "Biology",
         "completion_year" : 2010,
         "faculty" : "Science",
         "gradcampaign" : 1
      },
      {
         "level" : "Bachelor",
         "major" : "Biology",
         "completion_year" : 2008,
         "faculty" : "Science"
      }
   ],
   "school_email" : "cfranklin@example.edu",
   "email" : "christine@example.com"
}
{
   "_id" : 2,
   "name" : "Reyansh Sengupta",
   "degrees" : [
      {
         "level" : "Bachelor",
         "major" : "Chemical Engineering",
         "completion_year" : 2002,
         "faculty" : "Engineering"
      }
   ],
   "school_email" : "rsengupta2@example.edu"
}

$[]一起更新嵌套数组

$ [<identifier>]过滤后的位置运算符与$[]所有位置运算符一起,可用于更新嵌套数组。

students3使用以下文档创建一个集合:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
db.students3.insert(
   { "_id" : 1,
      "grades" : [
        { type: "quiz", questions: [ 10, 8, 5 ] },
        { type: "quiz", questions: [ 8, 9, 6 ] },
        { type: "hw", questions: [ 5, 4, 3 ] },
        { type: "exam", questions: [ 25, 10, 23, 0 ] },

      ]
   }
)

如果关联的grades.type字段为quiz,则以下内容将更新嵌套的grades.questions数组中大于或等于8的值。

1
2
3
4
5
db.students3.update(
   {},
   { $inc: { "grades.$[t].questions.$[score]": 2 } },
   { arrayFilters: [ { "t.type": "quiz" } , { "score": { $gte: 8 } } ], multi: true}
)

操作后,集合具有以下文档:

1
2
3
4
5
6
7
8
9
{
   "_id" : 1,
   "grades" : [
      { "type" : "quiz", "questions" : [ 12, 10, 5 ] },
      { "type" : "quiz", "questions" : [ 10, 11, 6 ] },
      { "type" : "hw", "questions" : [ 5, 4, 3 ] },
      { "type" : "exam", "questions" : [ 25, 10, 23, 0 ] }
   ]
}

要更新所有大于或等于8嵌套grades.questions数组中的值,无视type:

1
2
3
4
5
db.students3.update(
   {},
   { $inc: { "grades.$[].questions.$[score]": 2 } },
   { arrayFilters: [  { "score": { $gte: 8 } } ], multi: true}
)

$addToSet

除非该值已存在,否则$addToSet运算符会向该数组添加一个值,在这种情况下,$addToSet对该数组不执行任何操作。

$addToSet的形式为:

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

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

特性

$addToSet仅确保没有重复项添加到集合中,并且不影响现有重复项。 $addToSet不保证修改后的集合中元素的特定顺序。

缺少字段

如果$addToSet在文档中不存在的字段上进行更新,请$addToSet使用指定值作为元素创建数组字段。

字段不是数组

如果$addToSet在不是数组的字段上使用,该操作将失败。例如,考虑foo包含非数组字段的集合中的文档 colors。

1
{ _id: 1, colors: "blue,green,red" }

$addToSet对非数组字段的以下操作 colors失败:

1
2
3
4
db.foo.update(
   { _id: 1 },
   { $addToSet: { colors: "c" } }
)

要添加的值是一个数组

如果该值为数组,则$addToSet将整个数组作为单个元素附加。

考虑test包含数组字段的集合中的文档letters:

1
{ _id: 1, letters: ["a", "b"] }

以下操作将数组[“ c”,“ d”]追加到letters字段:

1
2
3
4
db.test.update(
   { _id: 1 },
   { $addToSet: { letters: [ "c", "d" ] } }
)

letters数组现在包含[“ c”,“ d”]数组作为元素:

1
{ _id: 1, letters: [ "a", "b", [ "c", "d" ] ] }

TIP:

要分别添加值的每个元素,请将$each修饰符与$addToSet一起使用。 有关详细信息,请参见$each修饰符。

要添加的值是一个文档

如果值为文档,则如果数组中的现有文档与要添加的文档完全匹配,则MongoDB会确定该文档为重复文档;也就是说,现有文档具有完全相同的字段和值,并且字段的顺序相同。因此,字段顺序很重要,您不能指定MongoDB仅比较文档中字段的子集来确定文档是否与现有数组元素重复。

例子

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

1
{ _id: 1, item: "polarizing_filter", tags: [ "electronics", "camera" ] }

添加到数组

由于数组中不存在此元素"accessories",因此以下操作将tags:“accessories"添加到数组中:

1
2
3
4
db.inventory.update(
   { _id: 1 },
   { $addToSet: { tags: "accessories" } }
)

值已经存在

以下$addToSet操作无效,因为 “camera"它已经是tags数组的元素:

1
2
3
4
db.inventory.update(
   { _id: 1 },
   { $addToSet: { tags: "camera"  } }
)

$each修饰符

您可以将$addToSet运算符与$each修饰符一起使用。 $each修饰符允许$addToSet运算符将多个值添加到数组字段。

集合inventory具有以下文档:

1
{ _id: 2, item: "cable", tags: [ "electronics", "supplies" ] }

然后,以下操作将$addToSet运算符与$each修饰符一起使用,以将多个元素添加到tags数组中:

1
2
3
4
db.inventory.update(
   { _id: 2 },
   { $addToSet: { tags: { $each: [ "camera", "electronics", "accessories" ] } } }
 )

操作对tags数组仅增加"camera"以及"accessories”,因为"electronics"数组中已经存在:

1
2
3
4
5
{
  _id: 2,
  item: "cable",
  tags: [ "electronics", "supplies", "camera", "accessories" ]
}

$pop

$pop运算符删除数组的第一个或最后一个元素。传递$pop值为-1删除数组的第一个元素,传递1删除数组的最后一个元素。

$pop的形式为:

1
{ $pop: { <field>: <-1 | 1>, ... } }

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

特性

如果<field>不是数组,则$ pop操作失败。

如果$pop运算符删除了<field>中的最后一项,则<field>将保存一个空数组。

例子

删除数组的第一个项目

给定以下文件的集合students:

1
{ _id: 1, scores: [ 8, 9, 10 ] }

以下示例删除了数组中的第一个元素scores(8) :

1
db.students.update( { _id: 1 }, { $pop: { scores: -1 } } )

操作后,将scores数组中的第一项删除:

1
{ _id: 1, scores: [ 9, 10 ] }

删除数组的最后一项

给定以下文件的集合students:

1
{ _id: 1, scores: [ 9, 10 ] }

以下示例通过在$ pop表达式中指定1来删除scores数组中的最后一个元素(10):

1
db.students.update( { _id: 1 }, { $pop: { scores: 1 } } )

操作后,更新后的文档将最后一个项目10 从其scores数组中删除:

1
{ _id: 1, scores: [ 9 ] }

$pull

$pull运算符从现有数组中删除一个或多个与指定条件匹配的值的所有实例。

$pull运算符的形式为:

1
{ $pull: { <field1>: <value|condition>, <field2>: <value|condition>, ... } }

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

特性

如果指定<condition>并且数组元素是嵌入式文档,则$pull运算符将应用<condition>就像每个数组元素都是集合中的文档一样。

如果要删除的指定<value>是数组,则$ pull仅删除与指定的<value>完全匹配的数组元素,包括顺序。

如果要删除的指定<value>是文档,则$ pull仅删除数组中具有完全相同的字段和值的元素。字段的顺序可以不同。

例子

删除所有等于指定的值的项目

给定stores集合中的以下文档:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
   _id: 1,
   fruits: [ "apples", "pears", "oranges", "grapes", "bananas" ],
   vegetables: [ "carrots", "celery", "squash", "carrots" ]
}
{
   _id: 2,
   fruits: [ "plums", "kiwis", "oranges", "bananas", "apples" ],
   vegetables: [ "broccoli", "zucchini", "carrots", "onions" ]
}

以下操作更新集合中的所有文档,以从fruits中除去“苹果”和“橙子”,并从vegetables中除去“carrots”:

1
2
3
4
5
db.stores.update(
    { },
    { $pull: { fruits: { $in: [ "apples", "oranges" ] }, vegetables: "carrots" } },
    { multi: true }
)

操作之后,fruits数组不再包含任何“apples”或“oranges”值,而蔬菜数组不再包含任何“carrots”值:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "_id" : 1,
  "fruits" : [ "pears", "grapes", "bananas" ],
  "vegetables" : [ "celery", "squash" ]
}
{
  "_id" : 2,
  "fruits" : [ "plums", "kiwis", "bananas" ],
  "vegetables" : [ "broccoli", "zucchini", "onions" ]
}

删除所有符合指定$pull条件的项目

给定profiles集合中的以下文档:

1
{ _id: 1, votes: [ 3, 5, 6, 7, 7, 8 ] }

下面的操作将从votes数组中删除所有大于或等于($gte)6的项目:

1
db.profiles.update( { _id: 1 }, { $pull: { votes: { $gte: 6 } } } )

更新操作后,文档的值仅小于6:

1
{ _id: 1, votes: [  3,  5 ] }

从文档数组中删除项目

一个survey集合包含以下文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
   _id: 1,
   results: [
      { item: "A", score: 5 },
      { item: "B", score: 8, comment: "Strongly agree" }
   ]
}
{
   _id: 2,
   results: [
      { item: "C", score: 8, comment: "Strongly agree" },
      { item: "B", score: 4 }
   ]
}

以下操作将从results数组中删除所有既包含得分字段等于8又包含item字段等于“B”的元素:

1
2
3
4
5
db.survey.update(
  { },
  { $pull: { results: { score: 8 , item: "B" } } },
  { multi: true }
)

$pull表达式将条件应用于结果数组的每个元素,就好像它是顶级文档一样。

操作之后,results数组将不包含score字段等于8且item字段等于“ B”的文档。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
   "_id" : 1,
   "results" : [ { "item" : "A", "score" : 5 } ]
}
{
  "_id" : 2,
  "results" : [
      { "item" : "C", "score" : 8, "comment" : "Strongly agree" },
      { "item" : "B", "score" : 4 }
   ]
}

因为$pull运算符将其查询应用于每个元素,就好像它是顶级对象一样,该表达式不需要使用$elemMatch来指定等于8的score字段和等于“B”的item字段的条件。实际上,以下操作不会从原始集合中提取任何元素。

1
2
3
4
5
db.survey.update(
  { },
  { $pull: { results: { $elemMatch: { score: 8 , item: "B" } } } },
  { multi: true }
)

但是,如果survey集合包含以下文档,则该results数组包含的嵌入式文档也包含数组:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
   _id: 1,
   results: [
      { item: "A", score: 5, answers: [ { q: 1, a: 4 }, { q: 2, a: 6 } ] },
      { item: "B", score: 8, answers: [ { q: 1, a: 8 }, { q: 2, a: 9 } ] }
   ]
}
{
   _id: 2,
   results: [
      { item: "C", score: 8, answers: [ { q: 1, a: 8 }, { q: 2, a: 7 } ] },
      { item: "B", score: 4, answers: [ { q: 1, a: 0 }, { q: 2, a: 8 } ] }
   ]
}

然后,您可以使用$elemMatch在Answers数组的元素上指定多个条件:

1
2
3
4
5
db.survey.update(
  { },
  { $pull: { results: { answers: { $elemMatch: { q: 2, a: { $gte: 8 } } } } } },
  { multi: true }
)

该操作从结果数组中删除了那些包含answer字段的嵌入式文档,这些文档包含至少一个q等于2且大于或等于8的元素:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
   "_id" : 1,
   "results" : [
      { "item" : "A", "score" : 5, "answers" : [ { "q" : 1, "a" : 4 }, { "q" : 2, "a" : 6 } ] }
   ]
}
{
   "_id" : 2,
   "results" : [
      { "item" : "C", "score" : 8, "answers" : [ { "q" : 1, "a" : 8 }, { "q" : 2, "a" : 7 } ] }
   ]
}

$push

$push运算符将指定的值附加到数组。

$push运算符的形式为:

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

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

特性

如果文档中不存在要更新的字段,则$push将以值作为元素的数组字段添加。

如果该字段不是数组,则操作将失败。

如果该值为数组,则$push将整个数组作为单个元素附加。要分别添加值的每个元素,请将$each修饰符与$push一起使用。

Modifiers

您可以将$push运算符与以下修饰符一起使用:

您可以将$push运算符与以下修饰符一起使用:

修饰符 描述
$each 将多个值附加到数组字段。
$slice 限制数组元素的数量。需要使用 $each修饰符。
$sort 排序数组的元素。需要使用 $each修饰符。
$position 指定要在数组中插入新元素的位置。需要使用$each修饰符。如果没有$position修饰符,则将$push 元素追加到数组的末尾。

与修饰符一起使用时,$push运算符具有以下形式:

1
{ $push: { <field1>: { <modifier1>: <value1>, ... }, ... } }

push不管修饰符出现的顺序如何,使用修饰符进行的操作的处理均按以下顺序进行:

  1. 更新数组以将元素添加到正确的位置。
  2. 如果指定,则应用排序。
  3. 切片数组(如果指定)。
  4. 存储数组。

例子

将值附加到数组

下面的示例追加89到scores数组:

1
2
3
4
db.students.update(
   { _id: 1 },
   { $push: { scores: 89 } }
)

将多个值追加到数组中

$push$each修饰符一起使用可将多个值附加到数组字段。

下面的示例将[90、92、85]的每个元素附加到名称字段等于joe的文档的scores数组中:

1
2
3
4
db.students.update(
   { name: "joe" },
   { $push: { scores: { $each: [ 90, 92, 85 ] } } }
)

$push运算符与多个修饰符一起使用

集合students具有以下文档:

1
2
3
4
5
6
7
8
9
{
   "_id" : 5,
   "quizzes" : [
      { "wk": 1, "score" : 10 },
      { "wk": 2, "score" : 8 },
      { "wk": 3, "score" : 5 },
      { "wk": 4, "score" : 6 }
   ]
}

以下$push操作使用:

  • $each修饰符可将多个文档添加到quizzes数组中,
  • $sort修饰符可按分数字段的降序对修改后的quizzes数组的所有元素进行排序,并且
  • $slice修饰符仅保留quizzes数组的前三个排序元素。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
db.students.update(
   { _id: 5 },
   {
     $push: {
       quizzes: {
          $each: [ { wk: 5, score: 8 }, { wk: 6, score: 7 }, { wk: 7, score: 6 } ],
          $sort: { score: -1 },
          $slice: 3
       }
     }
   }
)

该操作的结果是quizzes数组仅保留三个最高得分:

1
2
3
4
5
6
7
8
{
  "_id" : 5,
  "quizzes" : [
     { "wk" : 1, "score" : 10 },
     { "wk" : 2, "score" : 8 },
     { "wk" : 5, "score" : 8 }
  ]
}

$pullAll

$pullAll运算符将从现有数组中删除所有指定值的实例。与$pull运算符通过指定查询删除元素不同,$pullAll删除与列出的值匹配的元素。

$pullAll运算符的形式为:

1
{ $pullAll: { <field1>: [ <value1>, <value2> ... ], ... } }

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

特性

如果要删除的<value>是文档或数组,则$pullAll仅删除与指定的<value>完全匹配的数组元素,包括顺序。

示例

给定survey集合中的以下文档:

1
{ _id: 1, scores: [ 0, 2, 5, 5, 1, 0 ] }

以下操作从scores数组中删除值0和5的所有实例:

1
db.survey.update( { _id: 1 }, { $pullAll: { scores: [ 0, 5 ] } } )

操作完成后,更新后的文档将从“分数”字段中删除了所有实例0和5:

1
{ "_id" : 1, "scores" : [ 2, 1 ] }

$each

$each修饰符可与$addToSet运算符和$push运算符一起使用。

如果值在<field>中不存在,请与$addToSet运算符一起使用,以将多个值添加到数组<field>中。

1
{ $addToSet: { <field>: { $each: [ <value1>, <value2> ... ] } } }

$push运算符一起使用,可以将多个值附加到数组<field>中。

1
{ $push: { <field>: { $each: [ <value1>, <value2> ... ] } } }

$push运算符可以将$each修饰符与其他修饰符一起使用。有关$push可用的修饰符的列表,请参见修饰符。

例子

$each$push运算符一起使用

下面的示例将[90、92、85]的每个元素附加到名称字段等于joe的文档的scores数组中:

1
2
3
4
db.students.update(
   { name: "joe" },
   { $push: { scores: { $each: [ 90, 92, 85 ] } } }
)

$each$addToSet运算符一起使用

集合inventory具有以下文档:

1
{ _id: 2, item: "cable", tags: [ "electronics", "supplies" ] }

然后,以下操作将$addToSet运算符与$each修饰符一起使用,以将多个元素添加到tags数组:

1
2
3
4
db.inventory.update(
   { _id: 2 },
   { $addToSet: { tags: { $each: [ "camera", "electronics", "accessories" ] } } }
 )

该操作仅向标签数组添加“camera”和“accessories”,因为数组中已经存在“electronics”:

1
2
3
4
5
{
  _id: 2,
  item: "cable",
  tags: [ "electronics", "supplies", "camera", "accessories" ]
}

$position

$position修饰符指定$push运算符在数组中插入元素的位置。如果没有$position修饰符,则$push运算符会将元素插入到数组的末尾。

要使用$position修饰符,它必须与$each修饰符一起出现。

1
2
3
4
5
6
7
8
{
  $push: {
    <field>: {
       $each: [ <value1>, <value2>, ... ],
       $position: <num>
    }
  }
}

在版本3.6中更改:$position可以接受一个负数组索引值来指示从末尾开始的位置,该位置从(但不包括)数组的最后一个元素开始计数。

<num> 根据从零开始的索引指示数组中的位置:

  • 从数组的开头开始,非负数对应于数组中的位置。如果<num>的值大于或等于数组的长度,则$position修饰符无效,$push将元素添加到数组的末尾。
  • 从(但不包括)数组的最后一个元素开始,负数对应于数组中的位置。例如,-1指示数组中最后一个元素之前的位置。如果在$each数组中指定多个元素 ,则最后添加的元素位于末尾的指定位置。如果的绝对值<num>大于或等于数组的长度,则将$push 元素添加到数组的开头。

例子

在数组的开头添加元素

考虑一个students包含以下文档的集合:

1
{ "_id" : 1, "scores" : [ 100 ] }

以下操作将更新scores字段,以将元素50、60和70添加到数组的开头:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
db.students.update(
   { _id: 1 },
   {
     $push: {
        scores: {
           $each: [ 50, 60, 70 ],
           $position: 0
        }
     }
   }
)

该操作生成以下更新的文档:

1
{ "_id" : 1, "scores" : [  50,  60,  70,  100 ] }

在数组中间添加元素

考虑一个students包含以下文档的集合:

1
{ "_id" : 1, "scores" : [  50,  60,  70,  100 ] }

以下操作将更新scores字段,以在数组索引2处添加元素20和30:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
db.students.update(
   { _id: 1 },
   {
     $push: {
        scores: {
           $each: [ 20, 30 ],
           $position: 2
        }
     }
   }
)

该操作生成以下更新的文档:

1
{ "_id" : 1, "scores" : [  50,  60,  20,  30,  70,  100 ] }

使用负索引将元素添加到数组中

在版本3.6中更改:$position可以接受一个负数组索引值来指示从末尾开始的位置,该位置从(但不包括)数组的最后一个元素开始计数。例如,-1 指示数组中最后一个元素之前的位置。

考虑一个students包含以下文档的集合:

1
{ "_id" : 1, "scores" : [  50,  60,  20,  30,  70,  100 ] }

以下操作为$position指定-2,以在最后一个元素之前两个位置的位置加90,然后在最后一个元素之前两个位置的位置加80。

重要

对于负索引位置,如果在$each数组中指定多个元素,则最后添加的元素位于末尾的指定位置。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
db.students.update(
   { _id: 1 },
   {
     $push: {
        scores: {
           $each: [ 90, 80 ],
           $position: -2
        }
     }
   }
)

该操作生成以下更新的文档:

1
{ "_id" : 1, "scores" : [ 50, 60, 20, 30, 90, 80, 70, 100 ] }

$slice

$slice修饰符在$push操作期间限制数组元素的数量。要从读取操作中投影或返回指定数量的数组元素,请参阅$slice投影运算符。

要使用$slice修饰符,它必须与$each修饰符一起出现。您可以将一个空数组[]传递给$each修饰符,这样只有$slice修饰符才有效。

1
2
3
4
5
6
7
8
{
  $push: {
     <field>: {
       $each: [ <value1>, <value2>, ... ],
       $slice: <num>
     }
  }
}

<num>可以是:

描述
将数组更新为<field>空数组。
将数组更新为<field>仅包含最后<num>个元素。
要更新的数组<field>仅包含最前<num> 个元素。

特性

修饰符出现的顺序无关紧要。以前的版本要求$each修饰符与$slice一起使用时,它会作为第一个修饰符出现。

尝试在没有$each修饰符的情况下使用$ slice修饰符会导致错误。

例子

从数组末尾切片

集合students包含以下文档:

1
{ "_id" : 1, "scores" : [ 40, 50, 60 ] }

以下操作将新元素添加到scores数组,然后使用$slice修饰符将数组修剪为最后五个元素:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
db.students.update(
   { _id: 1 },
   {
     $push: {
       scores: {
         $each: [ 80, 78, 86 ],
         $slice: -5
       }
     }
   }
)

操作的结果是将更新后的scores数组的元素切为最后五个元素:

1
{ "_id" : 1, "scores" : [  50,  60,  80,  78,  86 ] }

从数组的前面切片

集合students包含以下文档:

1
{ "_id" : 2, "scores" : [ 89, 90 ] }

以下操作将新元素添加到scores数组,然后使用$slice修饰符将数组修剪为前三个元素。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
db.students.update(
   { _id: 2 },
   {
     $push: {
       scores: {
         $each: [ 100, 20 ],
         $slice: 3
       }
     }
   }
)

该操作的结果是将更新的scores数组的元素切片为前三个元素:

1
{ "_id" : 2, "scores" : [  89,  90,  100 ] }

仅使用分片更新数组

集合students包含以下文档:

1
{ "_id" : 3, "scores" : [  89,  70,  100,  20 ] }

要仅使用$slice修饰符的效果更新分数字段,请为$slice修饰符指定要切片的元素数(例如-3),为$each修饰符指定一个空数组[],如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
db.students.update(
  { _id: 3 },
  {
    $push: {
      scores: {
         $each: [ ],
         $slice: -3
      }
    }
  }
)

该操作的结果是将scores数组的元素切片为最后三个元素:

1
{ "_id" : 3, "scores" : [  70,  100,  20 ] }

$slice与其他$push修饰符一起使用

集合students具有以下文档:

1
2
3
4
5
6
7
8
9
{
   "_id" : 5,
   "quizzes" : [
      { "wk": 1, "score" : 10 },
      { "wk": 2, "score" : 8 },
      { "wk": 3, "score" : 5 },
      { "wk": 4, "score" : 6 }
   ]
}

以下$push操作使用:

  • $each修饰符可将多个文档添加到quizzes数组中,
  • $sort修饰符可按分数字段的降序对修改后的测quizzes数组的所有元素进行排序.
  • $slice修饰符仅保留quizzes数组的前三个排序元素。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
db.students.update(
   { _id: 5 },
   {
     $push: {
       quizzes: {
          $each: [ { wk: 5, score: 8 }, { wk: 6, score: 7 }, { wk: 7, score: 6 } ],
          $sort: { score: -1 },
          $slice: 3
       }
     }
   }
)

该操作的结果是quizzes仅保留三个最高得分:

1
2
3
4
5
6
7
8
{
  "_id" : 5,
  "quizzes" : [
     { "wk" : 1, "score" : 10 },
     { "wk" : 2, "score" : 8 },
     { "wk" : 5, "score" : 8 }
  ]
}

修饰符的顺序与修饰符的处理顺序无关。

$sort

$sort修饰符在$push操作期间对数组的元素进行排序。

要使用$sort修饰符,它必须与$each修饰符一起出现。您可以将一个空数组[]传递给$each修饰符,这样只有$sort修饰符才起作用。

1
2
3
4
5
6
7
8
{
  $push: {
     <field>: {
       $each: [ <value1>, <value2>, ... ],
       $sort: <sort specification>
     }
  }
}

对于:<sort specification>

  • 要对不是文档的数组元素进行排序,或者如果数组元素是文档,则要对整个文档进行排序,请指定1代表升序,-1代表降序。
  • 如果数组元素是文档,则要按文档中的字段排序,请指定具有字段和方向的排序文档,即{field:1}或{field:-1}。不要在排序规范中引用包含数组的字段(例如{“arrayField.field“:1}不正确)。

特性

$sort修饰符可以对不是文档的数组元素进行排序。在以前的版本中,$sort修饰符要求数组元素为文档。

如果数组元素是文档,则修饰符可以按整个文档或文档中的特定字段进行排序。在以前的版本中,$sort修饰符只能按文档中的特定字段排序。

尝试使用没有$each修饰符的$sort修饰符会导致错误。 $sort不再需要$slice修饰符。

例子

按文档中的字段对文档数组进行排序

集合students包含以下文档:

1
2
3
4
5
6
7
{
  "_id": 1,
  "quizzes": [
    { "id" : 1, "score" : 6 },
    { "id" : 2, "score" : 9 }
  ]
}

以下更新将其他文档附加到quizzes数组,然后按升序对数组的所有元素score进行排序 :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
db.students.update(
   { _id: 1 },
   {
     $push: {
       quizzes: {
         $each: [ { id: 3, score: 8 }, { id: 4, score: 7 }, { id: 5, score: 6 } ],
         $sort: { score: 1 }
       }
     }
   }
)

重要

排序文档直接引用文档中的字段,而不引用包含的数组quizzes字段;即{ score: 1 } ,而不是{“quizzes.score”:1}

更新后,数组元素按score字段升序排列 :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "_id" : 1,
  "quizzes" : [
     { "id" : 1, "score" : 6 },
     { "id" : 5, "score" : 6 },
     { "id" : 4, "score" : 7 },
     { "id" : 3, "score" : 8 },
     { "id" : 2, "score" : 9 }
  ]
}

对不是文档的数组元素进行排序

集合students包含以下文档:

1
{ "_id" : 2, "tests" : [  89,  70,  89,  50 ] }

以下操作将另外两个元素添加到scores数组并对元素进行排序:

1
2
3
4
db.students.update(
   { _id: 2 },
   { $push: { tests: { $each: [ 40, 60 ], $sort: 1 } } }
)

更新的文档具有scores按升序排列的数组元素:

1
{ "_id" : 2, "tests" : [  40,  50,  60,  70,  89,  89 ] }

使用仅排序更新数组

集合students包含以下文档:

1
{ "_id" : 3, "tests" : [  89,  70,  100,  20 ] }

要更新测试字段以使其元素降序排序,请指定{$ sort:-1}并为$each修饰符指定一个空数组[],如下所示:

1
2
3
4
db.students.update(
   { _id: 3 },
   { $push: { tests: { $each: [ ], $sort: -1 } } }
)

该操作的结果是更新scores字段以按降序对其元素排序:

1
{ "_id" : 3, "tests" : [ 100,  89,  70,  20 ] }

$sort$push一起使用

集合students具有以下文档:

1
2
3
4
5
6
7
8
9
{
   "_id" : 5,
   "quizzes" : [
      { "wk": 1, "score" : 10 },
      { "wk": 2, "score" : 8 },
      { "wk": 3, "score" : 5 },
      { "wk": 4, "score" : 6 }
   ]
}

以下$push操作使用:

  • $each修饰符可将多个文档添加到quizzes数组中,
  • $sort修饰符可按score字段的降序对修改后的quizzes数组的所有元素进行排序.
  • $slice修饰符仅保留quizzes数组的前三个排序元素。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
db.students.update(
   { _id: 5 },
   {
     $push: {
       quizzes: {
          $each: [ { wk: 5, score: 8 }, { wk: 6, score: 7 }, { wk: 7, score: 6 } ],
          $sort: { score: -1 },
          $slice: 3
       }
     }
   }
)

该操作的结果是仅保留三个最高得分测验:

1
2
3
4
5
6
7
8
{
  "_id" : 5,
  "quizzes" : [
     { "wk" : 1, "score" : 10 },
     { "wk" : 2, "score" : 8 },
     { "wk" : 5, "score" : 8 }
  ]
}

修饰符的顺序与修饰符的处理顺序无关。