【问题标题】:Finding intersection between two object arrays based on field基于字段查找两个对象数组之间的交集
【发布时间】:2018-04-25 20:09:22
【问题描述】:

在 mongo 集合中,我有以下结构的文档。

{
    "_id" : "Suzuki",
    "qty" : 10,
    "plates" : [ 
        {
            "rego" : "1QX-WA-123",
            "date" : 1516374000000.0
        }, 
        {
            "rego" : "1QX-WA-456",
            "date" : 1513369800000.0
        }
    ],
    "accounts" : [ 
        {
            "_id" : "23kpi9MD4KnTvnaW7",
            "createdAt" : 1513810712802.0,
            "date" : 1503446400000.0,
            "type" : "Suzuki",
            "rego" : "1QX-WA-123",
        }, 
        {
            "_id" : "2Wqrd4yofvLmqLm5H",
            "createdAt" : 1513810712802.0,
            "date" : 1501632000000.0,
            "type" : "Suzuki",
            "rego" : "1QX-WA-111",
        }
    ]
}

我正在尝试过滤accounts 数组中的对象,使其仅包含rego 存在于plates 数组中的那些对象。

我尝试了以下查询,但是它抛出了一个错误:all operands of $setIntersection must be arrays. One argument if of type object.

db.getCollection('dummy').aggregate([{
    $project: {
        plates: 1, 
        accounts: 1,
        intersect: {
            $setIntersection: [
                { $arrayElemAt: [ "$plates", 0 ] },
                { $arrayElemAt: [ "$accounts", 4 ] }
            ]
        }
    }
}])

我正在寻找的预期输出是:

{
    "_id" : "Suzuki",
    "qty" : 10,
    "plates" : [ 
        {
            "rego" : "1QX-WA-123",
            "date" : 1516374000000.0
        }, 
        {
            "rego" : "1QX-WA-456",
            "date" : 1513369800000.0
        }
    ],
    "accounts" : [ 
        {
            "_id" : "23kpi9MD4KnTvnaW7",
            "createdAt" : 1513810712802.0,
            "date" : 1503446400000.0,
            "type" : "Suzuki",
            "rego" : "1QX-WA-123",
        }
    ]
}

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    所以有几种方法,但你真正想要的只是$filter

    使用$in 可能是首选:

    db.getCollection('dummy').aggregate([
      { "$addFields": {
        "accounts": {
          "$filter": {
            "input": "$accounts",
            "cond": {
              "$in": [ "$$this.rego", "$plates.rego" ]
            }
          }
        }
      }}
    ])
    

    或者,如果您至少没有 MongoDB 3.4,那么使用$anyElementTrue

    db.getCollection('dummy').aggregate([
      { "$project": {
        "qty": 1,
        "plates": 1,
        "accounts": {
          "$filter": {
            "input": "$accounts",
            "as": "acc",
            "cond": {
              "$anyElementTrue": {
                "$map": {
                  "input": "$plates.rego",
                  "as": "rego",
                  "in": { "$eq": [ "$$rego", "$$acc.rego" ] }
                }
              }
            }
          }
        }
      }}
    ])
    

    甚至$setIsSubset:

    db.getCollection('dummy').aggregate([
      { "$project": {
        "qty": 1,
        "plates": 1,
        "accounts": {
          "$filter": {
            "input": "$accounts",
            "as": "acc",
            "cond": {
              "$setIsSubset": [ ["$$acc.rego"], "$plates.rego" ]
            }
          }
        }
      }}
    ])
    

    对于这种类型的操作,它真的不是$setIntersection,因为这需要将“仅字段值”作为“集合”进行比较,并且输出实际上只是“那个”而不是“对象” .

    您可以通过将数组索引与生成的“集合”位置匹配来做一些愚蠢的事情:

    db.getCollection('dummy').aggregate([
      { "$addFields": {
        "accounts": {
          "$map": { 
            "input": { "$setIntersection": ["$plates.rego", "$accounts.rego"] },
            "in": {
              "$arrayElemAt": [
                "$accounts",
                { "$indexOfArray": [ "$accounts.rego", "$$this" ] }      
              ]
            }
          }
        }
      }}
    ])
    

    但实际上,您可能真的只是希望$filter 结果更实用。如果您希望将该输出作为一个“集合”,那么您可以简单地使用 $setDifference 或类似运算符包装 $filter 输出,以使条目“唯一”。

    在所有变体中,这些返回:

    {
        "_id" : "Suzuki",
        "qty" : 10.0,
        "plates" : [ 
            {
                "rego" : "1QX-WA-123",
                "date" : 1516374000000.0
            }, 
            {
                "rego" : "1QX-WA-456",
                "date" : 1513369800000.0
            }
        ],
        "accounts" : [ 
            {
                "_id" : "23kpi9MD4KnTvnaW7",
                "createdAt" : 1513810712802.0,
                "date" : 1503446400000.0,
                "type" : "Suzuki",
                "rego" : "1QX-WA-123"
            }
        ]
    }
    

    "accounts" 数组中的项目显示为与"plates" 数组中的相应"rego" 数量匹配“过滤”

    【讨论】:

      猜你喜欢
      • 2022-07-30
      • 2021-11-14
      • 2020-12-22
      • 2021-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-14
      • 1970-01-01
      相关资源
      最近更新 更多