是否可以在 MongoDB $match 聚合阶段按字段过滤嵌套数组对象?
Is it possible to filter nested array objects by their fields in MongoDB $match aggregation stage?
我在 MongoDB 中有一个用户评论集合,用于存储用户对产品的评论。此外,我还有一个用户回复集合,其中包含对用户评论的回复。
用户评论具有以下文档结构:
{
username: 'John',
content: 'I liked the product',
}
用户回复具有以下文档结构:
{
username: 'John',
content: 'I liked the product',
userReviewId: ObjectID('blabla...'),
status: 'REJECTED' // or can be 'APPROVED'
}
我想进行聚合,以查找所有回复状态为 APPROVED
的用户评论。我在 MongoDB shell:
中尝试了以下聚合
db.getCollection('UserReview').aggregate(
[
{
"$lookup": {
"from": "UserReply",
"localField": "_id",
"foreignField": "userReview",
"as": "replies"
}
},
{
"$match": {
"replies": {
"$elemMatch": {"status":"REJECTED"}
}
}
}
]
)
如果某个用户评论有被批准和拒绝的回复,上述查询将获取具有两种类型回复的用户评论,如下所示:
{
username: 'John',
content: 'I liked the product',
replies: [
{
content: 'reply1'
userReviewId: ObjectID('blabla...'),
status: 'REJECTED'
},
{
content: 'reply1'
userReviewId: ObjectID('blabla...'),
status: 'APPROVED'
}
]
}
但是我希望结果如下,即仅在 replies
用户评论字段中包含批准的回复:
{
username: 'John',
content: 'I liked the product',
replies: [
{
content: 'reply1'
userReviewId: ObjectID('blabla...'),
status: 'APPROVED' // or can be 'APPROVED'
}
]
}
我发现实际只获得批准回复的唯一方法是在投影阶段使用 $filter
操作:
$addFields: {
replies: {
$filter: {
input: '$replies',
as: 'reply',
cond: { $in: ['$$reply.status', ['APPROVED']] }
}
}
}
是否可以在 $match
阶段执行回复过滤,或者这只能在 projections/addFields 阶段执行?
您可以使用lookup with aggregation pipeline,
- 让 localField 与管道中的 foreignField 匹配,
$expr
匹配id,匹配status
在$and
条件下被批准
db.UserReview.aggregate([
{
"$lookup": {
"from": "UserReply",
"let": { id: "$_id" },
"pipeline": [
{
$match: {
$and: [
{ $expr: { $eq: ["$$id", "$userReviewId"] } },
{ status: "APPROVED" }
]
}
}
],
"as": "replies"
}
}
])
我在 MongoDB 中有一个用户评论集合,用于存储用户对产品的评论。此外,我还有一个用户回复集合,其中包含对用户评论的回复。
用户评论具有以下文档结构:
{
username: 'John',
content: 'I liked the product',
}
用户回复具有以下文档结构:
{
username: 'John',
content: 'I liked the product',
userReviewId: ObjectID('blabla...'),
status: 'REJECTED' // or can be 'APPROVED'
}
我想进行聚合,以查找所有回复状态为 APPROVED
的用户评论。我在 MongoDB shell:
db.getCollection('UserReview').aggregate(
[
{
"$lookup": {
"from": "UserReply",
"localField": "_id",
"foreignField": "userReview",
"as": "replies"
}
},
{
"$match": {
"replies": {
"$elemMatch": {"status":"REJECTED"}
}
}
}
]
)
如果某个用户评论有被批准和拒绝的回复,上述查询将获取具有两种类型回复的用户评论,如下所示:
{
username: 'John',
content: 'I liked the product',
replies: [
{
content: 'reply1'
userReviewId: ObjectID('blabla...'),
status: 'REJECTED'
},
{
content: 'reply1'
userReviewId: ObjectID('blabla...'),
status: 'APPROVED'
}
]
}
但是我希望结果如下,即仅在 replies
用户评论字段中包含批准的回复:
{
username: 'John',
content: 'I liked the product',
replies: [
{
content: 'reply1'
userReviewId: ObjectID('blabla...'),
status: 'APPROVED' // or can be 'APPROVED'
}
]
}
我发现实际只获得批准回复的唯一方法是在投影阶段使用 $filter
操作:
$addFields: {
replies: {
$filter: {
input: '$replies',
as: 'reply',
cond: { $in: ['$$reply.status', ['APPROVED']] }
}
}
}
是否可以在 $match
阶段执行回复过滤,或者这只能在 projections/addFields 阶段执行?
您可以使用lookup with aggregation pipeline,
- 让 localField 与管道中的 foreignField 匹配,
$expr
匹配id,匹配status
在$and
条件下被批准
db.UserReview.aggregate([
{
"$lookup": {
"from": "UserReply",
"let": { id: "$_id" },
"pipeline": [
{
$match: {
$and: [
{ $expr: { $eq: ["$$id", "$userReviewId"] } },
{ status: "APPROVED" }
]
}
}
],
"as": "replies"
}
}
])