MongoDB 拉取第一个匹配的嵌套数组项
MongoDB pull first matching nested array item
我有以下文件...
{ "_id": 2, "name": "Jane Doe", "phones": [ { "type": "Mobile", "digits": [ { "val": 1 }, { "val": 2 } ] }, { "type": "Mobile", "digits": [ { "val": 3 }, { "val": 4 } ] }, { "type": "Land", "digits": [ { "val": 5 }, { "val": 6 } ] } ] }
{ "_id": 1, "name": "John Doe", "phones": [ { "type": "Land", "digits": [ { "val": 1 }, { "val": 2 } ] }, { "type": "Mobile", "digits": [ { "val": 0 }, { "val": 3 }, { "val": 4 } ] }, { "type": "Mobile", "digits": [ { "val": 3 }, { "val": 4 }, { "val": 9 } ] } ] }
...以及以下 MongoDB 查询...
db.getCollection("persons").updateOne({"name": "John Doe"},
{
"$pull":
{
"phones.$[condition1].digits":
{
"val: { $in: [ 3, 4 ] }
}
}
},
{
arrayFilters:
[
{ "condition1.type": "Mobile" }
]
})
我的问题是查询删除了数组的最后两个元素:第二个文档 (John Doe) 的“phones”,我只想删除第一个(而不是最后一个有“ 9" 之间的数字)。我如何才能只删除第一个匹配的嵌套数组项?
查询
- 管道更新
- 减少手机,从
{"phones": [], "found": false}
开始
- 如果
[3,4]
是 digits.val
和 not found
的子集 => 忽略它
否则保留它(连接数组以添加成员)
$getField
从减少的 {"phones" : [...]}
中获取手机
*$pull
删除所有满足条件的元素,也许有更新运算符而不是管道更新的方法,但如果你找不到更紧凑的方法,这就有效
*reduce 的替代方法,可以是 2 个过滤器,一个保留不包含 [3,4] 的值,一个保留包含的值,从包含的那些,然后连接那些数组,只删除一个那些包含 [3,4]
update(
{"name": {"$eq": "John Doe"}},
[{"$set":
{"phones":
{"$getField":
{"field": "phones",
"input":
{"$reduce":
{"input": "$phones",
"initialValue": {"phones": [], "found": false},
"in":
{"$cond":
[{"$and":
[{"$not": ["$$value.found"]},
{"$setIsSubset": [[3, 4], "$$this.digits.val"]}]},
{"phones": "$$value.phones", "found": true},
{"phones": {"$concatArrays": ["$$value.phones", ["$$this"]]},
"found": "$$value.found"}]}}}}}}}])
我对这次更新没有真正的动机,所以我不确定逻辑的细节。我想我已经从字面上理解了 OP 的话和部分演示,并且我已经实施了 update
管道来解决所述问题。考虑到可能性的数量,这可能不是您要找的。我的管道与 非常相似,但逻辑略有不同,因此输出也不同。我期待 OP comments/questions 到 identify/clarify 任何差异 and/or 歧义。
db.collection.update({
"name": "John Doe"
},
[
{
"$set": {
"phones": {
"$getField": {
"field": "phones",
"input": {
"$reduce": {
"input": "$phones",
"initialValue": { "phones": [], "pullDone": false },
"in": {
"$cond": [
{
"$and": [
{ "$eq": [ "$$this.type", "Mobile" ] },
{ "$not": "$$value.pullDone" }
]
},
{
"pullDone": true,
"phones": {
"$concatArrays": [
"$$value.phones",
[
{
"$mergeObjects": [
"$$this",
{
"digits": {
"$filter": {
"input": "$$this.digits",
"as": "digit",
"cond": {
"$not": [ { "$in": [ "$$digit.val", [ 3, 4 ] ] } ]
}
}
}
}
]
}
]
]
}
},
{
"pullDone": "$$value.pullDone",
"phones": {
"$concatArrays": [ "$$value.phones", [ "$$this" ] ]
}
}
]
}
}
}
}
}
}
}
])
在 mongoplayground.net 上试用。
我有以下文件...
{ "_id": 2, "name": "Jane Doe", "phones": [ { "type": "Mobile", "digits": [ { "val": 1 }, { "val": 2 } ] }, { "type": "Mobile", "digits": [ { "val": 3 }, { "val": 4 } ] }, { "type": "Land", "digits": [ { "val": 5 }, { "val": 6 } ] } ] }
{ "_id": 1, "name": "John Doe", "phones": [ { "type": "Land", "digits": [ { "val": 1 }, { "val": 2 } ] }, { "type": "Mobile", "digits": [ { "val": 0 }, { "val": 3 }, { "val": 4 } ] }, { "type": "Mobile", "digits": [ { "val": 3 }, { "val": 4 }, { "val": 9 } ] } ] }
...以及以下 MongoDB 查询...
db.getCollection("persons").updateOne({"name": "John Doe"},
{
"$pull":
{
"phones.$[condition1].digits":
{
"val: { $in: [ 3, 4 ] }
}
}
},
{
arrayFilters:
[
{ "condition1.type": "Mobile" }
]
})
我的问题是查询删除了数组的最后两个元素:第二个文档 (John Doe) 的“phones”,我只想删除第一个(而不是最后一个有“ 9" 之间的数字)。我如何才能只删除第一个匹配的嵌套数组项?
查询
- 管道更新
- 减少手机,从
{"phones": [], "found": false}
开始
- 如果
[3,4]
是digits.val
和not found
的子集 => 忽略它
否则保留它(连接数组以添加成员) $getField
从减少的{"phones" : [...]}
中获取手机
*$pull
删除所有满足条件的元素,也许有更新运算符而不是管道更新的方法,但如果你找不到更紧凑的方法,这就有效
*reduce 的替代方法,可以是 2 个过滤器,一个保留不包含 [3,4] 的值,一个保留包含的值,从包含的那些,然后连接那些数组,只删除一个那些包含 [3,4]
update(
{"name": {"$eq": "John Doe"}},
[{"$set":
{"phones":
{"$getField":
{"field": "phones",
"input":
{"$reduce":
{"input": "$phones",
"initialValue": {"phones": [], "found": false},
"in":
{"$cond":
[{"$and":
[{"$not": ["$$value.found"]},
{"$setIsSubset": [[3, 4], "$$this.digits.val"]}]},
{"phones": "$$value.phones", "found": true},
{"phones": {"$concatArrays": ["$$value.phones", ["$$this"]]},
"found": "$$value.found"}]}}}}}}}])
我对这次更新没有真正的动机,所以我不确定逻辑的细节。我想我已经从字面上理解了 OP 的话和部分演示,并且我已经实施了 update
管道来解决所述问题。考虑到可能性的数量,这可能不是您要找的。我的管道与
db.collection.update({
"name": "John Doe"
},
[
{
"$set": {
"phones": {
"$getField": {
"field": "phones",
"input": {
"$reduce": {
"input": "$phones",
"initialValue": { "phones": [], "pullDone": false },
"in": {
"$cond": [
{
"$and": [
{ "$eq": [ "$$this.type", "Mobile" ] },
{ "$not": "$$value.pullDone" }
]
},
{
"pullDone": true,
"phones": {
"$concatArrays": [
"$$value.phones",
[
{
"$mergeObjects": [
"$$this",
{
"digits": {
"$filter": {
"input": "$$this.digits",
"as": "digit",
"cond": {
"$not": [ { "$in": [ "$$digit.val", [ 3, 4 ] ] } ]
}
}
}
}
]
}
]
]
}
},
{
"pullDone": "$$value.pullDone",
"phones": {
"$concatArrays": [ "$$value.phones", [ "$$this" ] ]
}
}
]
}
}
}
}
}
}
}
])
在 mongoplayground.net 上试用。