我有两个集Clients
,Forms
Clients
架构有以下记录
{
"_id" : ObjectId("5b0bd79adcbf901ee404d8c0"),
"Name" : "Danielle",
"Email" : "Janet@test.com",
"Projects" : [{
"_id" : ObjectId("5b1e6f3410ef671cf82404be"),
"Name" : "test",
"Description" : "ttet",
"Forms" : [
ObjectId("5b03ff291c70c513bc9dbfa8"),
ObjectId("5b16238f30491d1c643f7f28"),
ObjectId("5afc23f3382646009c5210ab"),
],
"IsActive" : true
}, {
"_id" : ObjectId("5b03ffc11c70c513bc9dbfb1"),
"Name" : "apadei ief",
"Description" : "ttasdadet",
"Forms" : [
ObjectId("5b03ff291c70c513bc9dbfa8"),
ObjectId("5b16238f30491d1c643f7f28")
],
"IsActive" : true
}, {
// array of projects
}
],
"IsDeleted" : false,
}
Forms
架构有以下记录
{
"_id" : ObjectId("5b03ff291c70c513bc9dbfa8"),
"Name" : "Employee Information",
"Description" : "",
"IsActive" : true
},
{
"_id" : ObjectId("5b16238f30491d1c643f7f28"),
"Name" : "test form",
"Description" : "",
"IsActive" : true
},
{
"_id" : ObjectId("5afc23f3382646009c5210ab"),
"Name" : "Android test",
"Description" : "",
"IsActive" : true
},
{
"_id" : ObjectId("5a6304ffc3c3f119fc0e60c8"),
"Name" : "feedback form",
"Description" : "",
"IsActive" : true
}
我希望输出如下所示
{
"_id" : ObjectId("5b0bd79adcbf901ee404d8c0"),
"Name" : "Danielle",
"Email" : "Janet@test.com",
"Projects" : [{
"_id" : ObjectId("5b1e6f3410ef671cf82404be"),
"Name" : "test",
"Description" : "ttet",
"Forms" : [{
"_id" : ObjectId("5b03ff291c70c513bc9dbfa8"),
"Name" : "Employee Information",
"Description" : "",
"IsActive" : true
}, {
"_id" : ObjectId("5b16238f30491d1c643f7f28"),
"Name" : "test form",
"Description" : "",
"IsActive" : true
}, {
"_id" : ObjectId("5afc23f3382646009c5210ab"),
"Name" : "Android test",
"Description" : "",
"IsActive" : true
}
],
"IsActive" : true
}, {
"_id" : ObjectId("5b03ffc11c70c513bc9dbfb1"),
"Name" : "apadei ief",
"Description" : "ttasdadet",
"Forms" : [{
"_id" : ObjectId("5b03ff291c70c513bc9dbfa8"),
"Name" : "Employee Information",
"Description" : "",
"IsActive" : true
}, {
"_id" : ObjectId("5b16238f30491d1c643f7f28"),
"Name" : "test form",
"Description" : "",
"IsActive" : true
}
],
"IsActive" : true
}, {
// array of projects
}
],
"IsDeleted" : false
}
根据输出,我希望表单应该来自Forms
个集合。
为此,我正在进行如下聚合,
db.Clients.aggregate([{
$match : {
_id : ObjectId("5a8528ed0290f7eca89e9a5f"),
IsDeleted : false
}
}, {
$addFields : {
"Forms" : {
$map : {
input : {
$map : {
input : "$Projects",
in : {
$arrayElemAt : [{
$objectToArray : "$$this"
}, 1]
},
}
},
in : "$$this.v"
}
}
}
}, {
$lookup : {
from : "Forms",
localField : "Projects.Forms",
foreignField : "_id",
as : "Forms"
}
}, {
$addFields : {
"Forms" : {
$arrayElemAt : ["$Forms", 0]
}
}
}
])
但是它给了我错误的输出,它只从一个项目中返回一个Form
。我希望每个Forms
中的每个Projects
。
你的答案对我来说很好,但如果我想在$ map中为
制作过滤器怎么办?$and: [{
$eq: ["$Projects.IsActive", true]
}, {
$eq: ["$Projects.IsDeleted", false]
}]
答案 0 :(得分:1)
由于您尝试使用的某些功能似乎可以使用MongoDB 3.6,因此您可以使用真正重要的功能。即$lookup
的“子管道”形式,允许声明表达式匹配:
db.Clients.aggregate([
{ "$match" : { "_id": ObjectId("5a8528ed0290f7eca89e9a5f"), "IsDeleted": false } },
{ "$lookup": {
"from": "Forms",
"let": {
"join": {
"$reduce": {
"input": "$Projects.Forms",
"initialValue": [],
"in": { "$concatArrays": [ "$$value", "$$this" ] }
}
}
},
"as": "join",
"pipeline": [
{ "$match": {
"$expr": { "$in": [ "$_id", "$$join" ] }
}}
]
}},
{ "$addFields": {
"Projects": {
"$map": {
"input": "$Projects",
"in": {
"$mergeObjects": [
"$$this",
{
"Forms": {
"$map": {
"input": "$$this.Forms",
"in": {
"$arrayElemAt": [
"$join",
{ "$indexOfArray": [ "$join._id", "$$this" ] }
]
}
}
}
}
]
}
}
},
"join": "$$REMOVE"
}}
])
在使用$lookup
和$reduce
后,您基本上执行$concatArrays
,以便将嵌套数组详细信息“展平”为匹配"Forms"
{{1}的单个列表值。这些可以与国外集合进行比较,以返回正确的相关项目。
如果外部集合中没有“缺失”项并且所有引用的项都匹配,那么实际上只需要使用$map
处理数组并交换{{}中的“已连接”内容。 1}}表示现有的ObjectId
值。再次,因为您正在使用MongoDB 3.6,您可以使用$mergeObjects
以使$map
操作更灵活,而无需明确命名所有属性。
此处的匹配是使用$indexOfArray
查找“匹配”和$arrayElemAt
以便提取该值并在$map
期间将其换出。
即使没有MongoDB 3.6,你仍然可以做同样的事情:
"Forms"
稍长一点,因为您需要在$lookup
之前添加“flattened”数组内容,然后还没有其他功能来完全启用$addFields
重新映射数组,以便我们请改用$project
。
两种方式都返回相同的东西:
ObjectId