【问题标题】:How can I include an empty array after using $match in mongodb aggregation在 mongodb 聚合中使用 $match 后如何包含一个空数组
【发布时间】:2021-12-16 15:34:38
【问题描述】:

我正在尝试获取具有空 cards 数组的 boards.lists 或一些未归档的卡片,但使用 $match$or 运算符不起作用。我该如何解决这个问题??

示例文档如下:

{
_id: ObjectId("616bcd746bfed71fdcf892c3"),
userId: ObjectId("611cb3a14f142d5d94daa395"),
name: "myworkspace",
description: "",
boards: [
 {
    _id: ObjectId("6175f8c69c03810ea8e7b31e"),
    name: 'myboard',
    color: '',
    labels: [
      { color: 'blue', title: 'project1' }
    ],
    lists: [
     {
       archived: true,
       _id: ObjectId("6175f8c69c03810ea8e7b321"),
       cards: []
     },
     {
       archived: false,
       _id: ObjectId("6175f8c69c03810ea8e7b322"),
       cards: []
     },
     {
       archived: false,
       _id: ObjectId("6175f8c69c03810ea8e7b323"),
       cards: [{
         _id: ObjectId("61721cbc3092d32970cf2fed")
         archived: true,
         labelSelected: [],
         title: "mycard",
         description: "",
         attachments: [],
         comments: []
       }]
     },
     {
       archived: false,
       _id: ObjectId("6175f8c69c03810ea8e7b324"),
       cards: [{
         _id: ObjectId("6175f8d09c03810ea8e7b32d")
         archived: false,
         labelSelected: [],
         title: "mycard",
         description: "",
         attachments: [],
         comments: []
       }]
     },
   ]
  }
 ]
}

我做了什么:

 docs = await WorkspaceModel.aggregate([
      { $match: { _id: mongoose.Types.ObjectId(workspaceId) } },
      { $unwind: "$boards" },
      { $match: { "boards._id": mongoose.Types.ObjectId(boardId) } },
      { $unwind: "$boards.lists" },
      { $match: { "boards.lists.archived": false } },
      {
        $unwind: {
          path: "$boards.lists.cards",
          preserveNullAndEmptyArrays: true,
        },
      },
      {  
        $match: {
          $or: [
             { "boards.lists.cards": { $exists: true, $size: 0 } },
             { "boards.lists.cards.archived": false }
           ]
         },
       },
      {
        $group: {
          _id: "$boards._id",
          name: { $first: "$boards.name" },
          color: { $first: "$boards.color" },
          labels: { $first: "$boards.labels" },
          lists: { $addToSet: "$boards.lists" },
        },
      },
    ]).exec();

我得到的是:[],在$match 语句之前,它只显示了所有未归档的列表。

我的期望:

[
  {
    _id: ObjectId("6175f8c69c03810ea8e7b31e"),
    name: 'myboard',
    color: '',
    labels: [
      { color: 'blue', title: 'project1' }
    ],
    lists: [
     {
       archived: false,
       _id: ObjectId("6175f8c69c03810ea8e7b322"),
       cards: []
     },
     {
       archived: false,
       _id: ObjectId("6175f8c69c03810ea8e7b324"),
       cards: [{
         _id: ObjectId("6175f8d09c03810ea8e7b32d")
         archived: false,
         labelSelected: [],
         title: "mycard",
         description: "",
         attachments: [],
         comments: []
       }]
     },
   ]
  }
]

【问题讨论】:

  • 你能在你的示例数据中返回具体的 objectIds 吗?如果没有办法映射 objectId,就很难理解您的预期输出。 Here 是一个试用版,我猜您只是想删除所有 archived: true 条目。
  • 您的示例文档没有任何boards,因此很难看到您真正想要得到什么。
  • 你可以用$filter代替$unwind$match

标签: mongodb mongoose aggregation-framework


【解决方案1】:

这是我的解决方案:

  1. $filter 非归档列表优先并用作$map 的输入
  2. $filter 未存档或空卡并将结果映射到每个列表
  3. 它将显示没有卡片或未归档卡片的未归档列表
 docs = await WorkspaceModel.aggregate([
      { $match: { _id: mongoose.Types.ObjectId(workspaceId) } },
      { $unwind: "$boards" },
      { $match: { "boards._id": mongoose.Types.ObjectId(boardId) } },
      { $replaceRoot: { newRoot: "$boards" } },
      {
        $set: {
          lists: {
            $map: {
              input: {
                $filter: {
                  input: "$lists",
                  as: "list",
                  cond: {
                    $eq: ["$$list.archived", false],
                  },
                },
              },
              as: "filteredList",
              in: {
                title: "$$filteredList.title",
                cards: {
                  $filter: {
                    input: "$$filteredList.cards",
                    as: "card",
                    cond: {
                      $or: [
                        { $eq: ["$$card", []] },
                        { $eq: ["$$card.archived", false] },
                      ],
                    },
                  },
                },
              },
            },
          },
        },
      },
    ]).exec();

【讨论】:

    【解决方案2】:

    查询

    • 展开板
    • 从列表中只保留具有
      (and (= archived false) (or empty_cards cards_contains_not_archived_card)
    • 如果你想过滤掉空列表,你也可以添加一个匹配
      {"$match" : {"lists": {"$ne" : [] }}}
    • 在您的预期输出中,您没有 _id 来知道每个列表属于哪个文档,在下面的查询中也会发生同样的情况

    Test code here

    aggregate(
    [{"$unwind": {"path": "$boards"}},
     {"$replaceRoot": {"newRoot": "$boards"}},
     {"$set": 
       {"lists": 
         {"$filter": 
           {"input": "$lists",
            "cond": 
            {"$and": 
              [{"$eq": ["$$this.archived", false]},
               {"$or": 
                 [{"$eq": ["$$this.cards", []]},
                 {"$in": [false, "$$this.cards.archived"]}]}]}}}}}])
    

    【讨论】:

    • 我刚刚添加了错过的_ids。当我在代码中使用您的查询时,它按预期工作。和上面的 cmets 一样,使用 filter 是关键。非常感谢!
    • 在使用更多数据进行测试时,我稍微编辑了您的查询,因为 $in 运算符似乎不适用于非数组值,而且看起来效果很好。
    • 我们也有this,可能你用过这个,不妨看看。
    【解决方案3】:

    问题出在你的比赛上 根据您的示例数据,如果您需要,我可以使用 match 和 group 创建像这样的聚合,您可以更改或添加一些管道

    https://mongoplayground.net/p/SWr_q-bI9A5

    db.collection.aggregate([
      {
        "$unwind": "$lists"
      },
      {
        $match: {
          $or: [
            {
              "lists.cards": []
            },
            {
              "lists.cards": {
                $elemMatch: {
                  "archived": false
                }
              }
            }
          ]
        }
      },
      {
        "$group": {
          "_id": "_id",
          "lists": {
            "$addToSet": "$lists"
          },
          "name": {
            "$first": "$name"
          },
          "lables": {
            "$first": "$labels"
          },
          "color": {
            "$first": "$color"
          },
          
        }
      }
    ])
    

    【讨论】:

      猜你喜欢
      • 2019-03-27
      • 2021-10-24
      • 2017-04-25
      • 2022-07-09
      • 2015-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多