我的收藏文件是:
{
"_id" : 1,
"fruits" : [ {"name":"pears"},
{"name":"grapes"},
{"name":"bananas"} ],
}
{
"_id" : 2,
"fruits" : [ {"name":"bananas"} ],
}
当水果只包含“香蕉”时,我需要删除整个文件,或者当水果阵列中有多个水果时,我只需要去除水果“香蕉”。
运行必需查询后的最终收藏应为:
{
"_id" : 1,
"fruits" : [ {"name":"pears"},
{"name":"grapes"}],
}
我目前正在使用两个查询来完成此任务:
db.collection.remove({'fruits':{$size:1, $elemMatch:{'name': 'bananas'} }}) [this will remove the document when only one fruit present]
和
db.collection.update({},{$pull:{'fruits':{'name':'bananas'}}},{multi: true}) [this will remove the entry 'bananas' from the array]
有没有办法将这些组合成一个查询?
编辑:最后拍摄
- 我猜没有“一个查询”来执行上述任务,因为两个动作的意图非常不同。
- 可以执行的最佳操作是:将操作添加到bulk_write查询中,该查询可以保存在网络I / O上(如Neil的答案所示)。当您有多个此类操作被触发时,这被认为更有益。此外,bulk_write可以提供锁定功能,因为bulk_write的“有序”模式使操作顺序,中断并暂停执行,以防出错。
因此,当执行的操作需要按顺序执行时,bulk_write会更有用。有点像JS中的“链接”。还可以选择执行无序的bulk_writes。
此外,批量写入中指定的操作在collection level as individual actions.
答案 0 :(得分:2)
你基本上希望bulk_write()
在这里做到这两点。同时使用$exists
确保只有一个元素:
from pymongo import UpdateMany, DeleteMany
db.collection.bulk_write(
[
UpdateMany(
{ "fruits.1": { "$exists": True }, "fruits.name": "bananas" },
{ "$pull":{
'fruits': { 'name':'bananas' }
}}
),
DeleteMany(
{ "fruits.1": { "$exists": False }, "fruits.name": "bananas" }
)
],
ordered=False
)
你真的不需要$elemMatch
用于"一个"条件,您应该使用update_many()
,在这种情况下UpdateMany()
而不是{ "multi": true }
。这个选项在" pymongo"中是不同的。无论如何。当然,对于"批量"有delete_many()
或DeleteMany()
。上下文。
批量操作通过一个响应发送一个请求,这比发送多个请求更好。另外"更新"和"删除"是两个不同的东西,但单个请求可以像这样组合。
$size
运算符有效,但$exists
可以应用于"范围" $size
不能的地方,所以它通常更灵活。
,就像$exists
范围示例
# Array between 2 and 4 elements
db.collection.update_many(
{
"fruits.1": { "$exists": True },
"fruits.4": { "$exists": False },
"fruits.name": "bananas"
},
{ "$pull":{
'fruits': { 'name':'bananas' }
}}
)
当然,在这里的上下文中,你实际上想知道数组中其他可能的东西和只有"只有"单个"香蕉"。
这里的ordered=False
实际上指的是两种不同的方式"批量写"请求可以处理
有序 - True
("默认"),然后以"序列顺序"执行操作。因为它们出现在使用"批量写入"发送的操作数组中。如果此处发生任何错误,则批处理将在错误点停止执行并返回异常。
UnOrdered - False
操作在" parallel"中执行在合理的服务器限制范围内。如果发生任何错误,仍然会引发异常,但这并不会阻止"批量写入"从完成。使用"数组索引"返回任何错误。从提供给命令的列表中导致错误的操作。
此选项可用于"调整"期望的行为,特别是错误报告和延续,并且还允许一定程度的并行性"执行" serial"实际上并不需要操作。由于这两个陈述实际上并不依赖于其中一个,并且实际上会选择不同的文档,因此ordered=False
可能是效率方面更好的选择。
答案 1 :(得分:0)
db.users.aggregate(
[{
$project: {
data: {
$filter: {
input: "$fruits",
as: "filterData",
cond: { $ne: [ "$$filterData.name", 'bananas' ] }
}
}
}
},
{
$unwind: {
path : "$data",
preserveNullAndEmptyArrays : false
}
},
{
$group: {
_id:"$_id",
data: { $addToSet: "$data" }
}
},
])
我认为上面的查询可以给你完美的结果