在 mongodb 聚合中使用 $match 后如何包含一个空数组
How can I include an empty array after using $match in mongodb aggregation
我正在尝试获取具有空 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: []
}]
},
]
}
]
问题出在你的匹配上
根据您的示例数据,如果您需要,我可以使用匹配和组创建这样的聚合,您可以更改或添加一些管道
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"
},
}
}
])
查询
- 展开板
- 从列表中只保留具有
(and (= archived false) (or empty_cards cards_contains_not_archived_card)
- 如果您想过滤掉空列表,您也可以添加一个匹配项
{"$match" : {"lists": {"$ne" : [] }}}
- 在您的预期输出中,您没有 _id 来知道每个列表属于哪个文档,在下面的查询中会发生同样的情况
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"]}]}]}}}}}])
这是我的解决方案:
$filter
非存档列表首先用作 $map
的输入
$filter
非存档或空卡片并将结果映射到每个列表
- 它将显示没有卡片或有非存档卡片的非存档列表
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();
我正在尝试获取具有空 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: []
}]
},
]
}
]
问题出在你的匹配上 根据您的示例数据,如果您需要,我可以使用匹配和组创建这样的聚合,您可以更改或添加一些管道
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"
},
}
}
])
查询
- 展开板
- 从列表中只保留具有
(and (= archived false) (or empty_cards cards_contains_not_archived_card)
- 如果您想过滤掉空列表,您也可以添加一个匹配项
{"$match" : {"lists": {"$ne" : [] }}}
- 在您的预期输出中,您没有 _id 来知道每个列表属于哪个文档,在下面的查询中会发生同样的情况
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"]}]}]}}}}}])
这是我的解决方案:
$filter
非存档列表首先用作$map
的输入
$filter
非存档或空卡片并将结果映射到每个列表- 它将显示没有卡片或有非存档卡片的非存档列表
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();