【问题标题】:How can I do a intersection betwen several arrays?如何在多个数组之间进行交集?
【发布时间】:2021-10-10 19:21:42
【问题描述】:

我正在检索以下数据:

[
    {
        "_id": null,
        "count": 2,
        "students": [
            [
                "a",
                "b"
            ],
            [
                "a",
                "c",
                "d"
            ]
        ]
    }
]

使用这个查询:

aggregate([
    {
      $match: {
        class: {
          $in: classes,
        },
      },
    },
    {
      $project: { students: 1 },
    },
    {
      $group: {
        _id: null,
        count: { $sum: 1 },
        data: { $push: "$students" },
      },
    },
    {
      $project: {
        count: 1,
        students: {
          $setIntersection: "$data",
        },
      },
    },
])

但这个想法是,学生们成为这些数组的交叉点,以便只得到

[
    {
        "_id": null,
        "count": 2,
        "students": [
            [
                "a",
            ],
        ]
    }
]

我尝试了几种使用 setIntersection 的组合,但都没有奏效。

怎么才能只有那个路口?

谢谢。

【问题讨论】:

    标签: node.js mongodb mongoose aggregation-framework


    【解决方案1】:

    多数组交集的概念类似于chridam's answer on How to find set intersection of sets between the documents in a single collection in MongoDB?

    1. $unwind:解构 students 数组字段以输出每个元素的文档。
    2. group:将多个文档分组得到initialStudent ($first)。
    3. $set:创建新字段common。使用$reduce 运算符来展平$setIntersection 的数组,从initialStudent$students 中的每个下一个元素开始。
    4. $project:在 (3) 中显示 student 字段,其中包含 common 的结果的嵌套数组。
    db.collection.aggregate([
      {
        "$unwind": "$students"
      },
      {
        "$group": {
          "_id": 0,
          count: {
            $sum: 1
          },
          "students": {
            "$push": "$students"
          },
          "initialStudent": {
            "$first": "$students"
          }
        }
      },
      {
        "$set": {
          "common": {
            "$reduce": {
              "input": "$students",
              "initialValue": "$initialStudent",
              "in": {
                "$setIntersection": [
                  "$$value",
                  "$$this"
                ]
              }
            }
          },
          
        }
      },
      {
        $project: {
          "count": 1,
          "students": [
            "$common"
          ]
        }
      }
    ])
    

    Sample Mongo Playground


    改进

    感谢@varman 对查询的建议,

    上述解决方案的管道 1 ($unwind) 和 2 ($group) 可以简化为 $set 管道以检索 $first$countstudents

    {
      $addFields: {
        "initialStudent": {
          "$first": "$students"
        },
        "count": {
          "$size": "$students"
        }
      }
    }
    

    【讨论】:

    • 您的回答很棒。我可以给出的一个小改进是 mongoplayground.net/p/dwFUuBwAo6S 。我们确实减少了 $unwind$group 的使用,因为两者都很昂贵。
    • 嗨@varman,感谢您的建议。是的,您的查询看起来更简单/缩短并且性能更好。非常感谢所提供的课程。 =)
    【解决方案2】:

    一种方法是在获取数据后进行交集。

    //assuming students has only two arrays.
    const IntersectedArray = students[0].filter(value => students[1].includes(value));
    

    【讨论】:

    • 可以有多个数组而不是两个,无论如何谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多