mongodb update操作数组
在上一篇mongodb update操作符之常用字段更新操作符中详细介绍了常用的字段更新操作符,本篇开始介绍操作数组需要用到的操作符以及运算修饰符。在MongoDB的模式中,我们经常将一些数据存储到数组类型中,即我们常见的嵌套模式设计的一种实现方式。数组的这种设计实现方式在关系数据库中是不常见的。关于数组的操作可以分成两类,一类是数组操作符,另一个是数组运算修饰符。
1. 数组操作符
1.1. $push
说明:
将特定的元素或值添加到数组中。可以与
语法:
{ $push: { <field1>: <value1>, ... } }
注意:如果要更新的文档中没有该字段,则$push将该值作为元素添加到数组字段中。
如果字段不是数组,操作将失败。
如果值是一个数组,$push将整个数组作为单个元素追加。要分别添加值的每个元素,请使用$push修饰符$each。
1.1.1. 示例
1.1.1.1. 向数组添加一个值
初始化数据:
db.inventory.insertOne({ _id: 1, item: "polarizing_filter", tags: [ ] })
示例:向数组添加一个值
db.inventory.update( { _id: 1 }, {$push: { tags: "test" } } )
更改后查询:
db.inventory.findOne({"_id":1})
返回结果:
{ _id: 1, item: 'polarizing_filter', tags: [ 'test' ] }
1.1.1.2. 向数组添加多个值
示例:向数组添加多个值
db.inventory.update(
{ _id: 1},
{ $push: { tags: { $each: [ "test1", "test", "test2" ] } } }
)
更改后查询:
db.inventory.findOne({"_id":1})
返回结果:
{ _id: 1,
item: 'polarizing_filter',
tags: [ 'test', 'test1', 'test', 'test2' ] }
1.2. $addToSet
说明:
只向集合中不存在的元素添加数组元素,$addToSet不保证修改后的集合中元素的特定顺序,如果你在一个不是数组的字段上使用$addToSet,操作将会失败,如果值是一个数组,$addToSet将整个数组作为单个元素追加。
语法:
{ $addToSet: { <field1>: <value1>, ... } }
1.2.1. 示例
初始化数据:
db.inventory.insertOne({ _id: 1, item: "polarizing_filter", tags: [ "electronics", "camera" ] })
注意:如果插入的值是在tags数组中已经存在,则不会插入。
1.2.1.1. 数组字段增加单个值
示例:追加accessories 值到tags数组字段中
db.inventory.update(
{ _id: 1 },
{ $addToSet: { tags: "accessories" } }
)
更改后查询:
db.inventory.findOne({"_id":1})
返回结果:
{ _id: 1,
item: 'polarizing_filter',
tags: [ 'electronics', 'camera', 'accessories' ] }
1.2.1.2. 数组字段增加多个值
示例:追加多个值到tags数组字段中
db.inventory.update(
{ _id: 1},
{ $addToSet: { tags: { $each: [ "test", "test1", "test2" ] } } }
)
更改后查询:
db.inventory.findOne({"_id":1})
返回结果:
{ _id: 1,
item: 'polarizing_filter',
tags: [ 'electronics', 'camera', 'accessories' ] }
1.3. $pop
说明:
$pop操作符删除数组的第一个或最后一个元素。给$pop传递一个值-1来删除数组中的第一个元素,1来删除数组中的最后一个元素。
语法:
{ $pop: { <field>: <-1 | 1>, ... } }
注意:如果<field>不是数组,则$pop操作失败。
如果$pop操作符删除<field>中的最后一项,那么<field>将保存一个空数组。
1.3.1. 示例
初始化数据:
db.inventory.insertOne({ _id: 1, item: "polarizing_filter", tags: [ "electronics", "camera" ] })
注意:如果插入的值是在tags数组中已经存在,则不会插入。
1.3.1.1. 删除数组字段第一个元素值
示例:追加accessories 值到tags数组字段中
db.inventory.update( { _id: 1 }, { $pop: { tags: -1 } } )
更改后查询:
db.inventory.findOne({"_id":1})
返回结果:
{ _id: 1,
item: 'polarizing_filter',
tags: [ 'camera'] }
1.3.1.2. 删除数组字段最后一个元素值
示例:追加多个值到tags数组字段中
db.inventory.update( { _id: 1 }, { $pop: { tags: 1 } } )
更改后查询:
db.inventory.findOne({"_id":1})
返回结果:
{ _id: 1,
item: 'polarizing_filter',
tags: [ ] }
1.4. $pull
说明:
$pull操作符从现有数组中删除一个值或与指定条件匹配的值的所有数组元素。可以与$each、$position、$slice、$sort一起使用
语法:
{ $pull: { <field1>: <value|condition>, <field2>: <value|condition>, ... } }
{ $push: { <field1>: { <modifier1>: <value1>, ... }, ... } }
1.4.1. 示例
1.4.1.1. 删除等于指定值的所有元素
初始化数据:
db.stores.insertMany([{
_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" ]
}])
示例:下面的操作更新集合中的所有文档,从数组fruit中删除“apples”和“oranges”,并从数组vegetables中删除“carrot”:
db.stores.update(
{ },
{ $pull: { fruits: { $in: [ "apples", "oranges" ] }, vegetables: "carrots" } },
{ multi: true }
)
更改后查询:
db.stores.find()
返回结果:
{ _id: 1,
fruits: [ 'pears', 'grapes', 'bananas' ],
vegetables: [ 'celery', 'squash' ] }
{ _id: 2,
fruits: [ 'plums', 'kiwis', 'bananas' ],
vegetables: [ 'broccoli', 'zucchini', 'onions' ] }
1.4.1.2. 删除所有与指定的$pull条件匹配的项
初始化数据:
db.profiles.insert({ _id: 1, votes: [ 3, 5, 6, 7, 7, 8 ] })
示例:下面的操作将从votes数组中删除大于或等于($gte) 6的所有元素:
db.profiles.update( { _id: 1 }, { $pull: { votes: { $gte: 6 } } } )
更改后查询:
db.profiles.find()
返回结果:
{ _id: 1, votes: [ 3, 5 ] }
1.4.1.3. 从文档数组中移除元素
初始化数据:
db.survey.insertMany([{
_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字段score等于8,item等于B的元素
db.survey.update(
{ },
{ $pull: { results: { score: 8 , item: "B" } } },
{ multi: true }
)
更改后查询:
db.survey.find()
返回结果:
{ _id: 1, results: [ { item: 'A', score: 5 } ] }
{ _id: 2,
results:
[ { item: 'C', score: 8, comment: 'Strongly agree' },
{ item: 'B', score: 4 } ] }
1.5. $pullAll
说明:
从数组中移除所有匹配的值。
语法:
{ $pullAll: { <field1>: [ <value1>, <value2> ... ], ... } }
1.5.1. 示例
初始化数据:
db.testPullAll.insert({ _id: 1, scores: [ 0, 2, 5, 5, 1, 0 ] })
示例:
db.testPullAll.update( { _id: 1 }, { $pullAll: { scores: [ 0, 5 ] } } )
更改后查询:
db.testPullAll.find()
返回结果:
{ _id: 1, scores: [ 2, 1 ] }
2. 数组运算修饰符
2.1. $each
说明:
与$push和$addToSet一起使用来操作多个值
语法:
{ $addToSet: { <field>: { $each: [ <value1>, <value2> ... ] } } }
{ $push: { <field>: { $each: [ <value1>, <value2> ... ] } } }
2.2. $slice
说明:
与$push和$each一起使用来缩小更新后数组的大小。
语法:
{
$push: {
<field>: {
$each: [ <value1>, <value2>, ... ],
$slice: <num>
}
}
}
2.3. $sort
说明:
与$push、$each、$slice一起来排序数组中的子文档。
语法:
{
$push: {
<field>: {
$each: [ <value1>, <value2>, ... ],
$sort: <sort specification>
}
}
}
2.4. $position
说明:
$position修饰符指定了$push操作符在数组中插入元素的位置。如果没有$position修饰符,$push操作符会将元素插入到数组的末尾,要使用$position修饰符,它必须与$each修饰符一起出现。
语法:
{
$push: {
<field>: {
$each: [ <value1>, <value2>, ... ],
$position: <num>
}
}
}
2.5. 使用带有多个修饰符的$push示例
初始化数据:
db.students.insert({
"_id" : 10,
"quizzes" : [
{ "wk": 1, "score" : 10 },
{ "wk": 2, "score" : 8 },
{ "wk": 3, "score" : 5 },
{ "wk": 4, "score" : 6 }
]
})
示例:以下$push操作使用:
将多个文档添加到quizzes数组的$each修饰符,
$sort修饰符按分数字段降序排序修改后的quizzes数组的所有元素
$slice修饰符只保留quizzes数组的前三个排序元素。
db.students.update(
{ _id: 10 },
{
$push: {
quizzes: {
$each: [ { wk: 5, score: 8 }, { wk: 6, score: 7 }, { wk: 7, score: 6 } ],
$position: 1,
$sort: { score: -1 },
$slice: 3
}
}
}
)
更改后查询:
db.students.find({"_id":10})
返回结果:
{ _id: 10,
quizzes:
[ { wk: 1, score: 10 },
{ wk: 2, score: 8 },
{ wk: 5, score: 8 } ] }