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.valnot found 的子集 => 忽略它
    否则保留它(连接数组以添加成员)
  • $getField 从减少的 {"phones" : [...]}
  • 中获取手机

*$pull 删除所有满足条件的元素,也许有更新运算符而不是管道更新的方法,但如果你找不到更紧凑的方法,这就有效

*reduce 的替代方法,可以是 2 个过滤器,一个保留不包含 [3,4] 的值,一个保留包含的值,从包含的那些,然后连接那些数组,只删除一个那些包含 [3,4]

Playmongo

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 上试用。