这是我的文件。
{
"_id" : ObjectId("589b6132fafb5a09549b46cb"),
"name" : "foo",
"users" : [
{
"_id" : ObjectId("589b6132fafb5a09549b46cc"),
"name" : "Peter",
"emails" : [
{
"address" : "peter@email.com"
},
{
"address" : "test2@email.com"
}
]
},
{
"_id" : ObjectId("589b6132fafb5a09549b46cd"),
"name" : "Joe",
"emails" : []
}
]
}
我正在展开用户和users.email 当我尝试重新组合时,我得到一个名为Peter的用户的副本,因为它有2封电子邮件。
查询:
db.test.aggregate([
{ "$unwind": {
"path": "$users",
"preserveNullAndEmptyArrays": true
} },
{ "$unwind": {
"path": "$users.emails",
"preserveNullAndEmptyArrays": true
} },
{
"$group": {
"_id": "$_id",
"name": { "$first": "$name" },
"users": { "$addToSet": "$users"},
"allEmails": { "$push": "$users.emails.address" }
}
}
])
结果:
{
"_id" : ObjectId("589b6132fafb5a09549b46cb"),
"name" : "foo",
"users" : [
{
"_id" : ObjectId("589b6132fafb5a09549b46cd"),
"name" : "Joe"
},
{
"_id" : ObjectId("589b6132fafb5a09549b46cc"),
"name" : "Peter",
"emails" : {
"address" : "test2@email.com"
}
},
{
"_id" : ObjectId("589b6132fafb5a09549b46cc"),
"name" : "Peter",
"emails" : {
"address" : "peter@email.com"
}
}
],
"allEmails" : [
"peter@email.com",
"test2@email.com"
]
}
在使用文档父级上的allEmails展开之前,我需要用户对象完全相同,如下例所示。
{
"_id" : ObjectId("589b6132fafb5a09549b46cb"),
"name" : "foo",
"users" : [
{
"_id" : ObjectId("589b6132fafb5a09549b46cc"),
"name" : "Peter",
"emails" : [
{ "address" : "test2@email.com" },
{ "address" : "peter@email.com" }
]
},
{
"_id" : ObjectId("589b6132fafb5a09549b46cd"),
"name" : "Joe",
"emails" : []
}
],
"allEmails" : [
"peter@email.com",
"test2@email.com"
]
}
答案 0 :(得分:1)
运行以下聚合管道应该可以得到所需的结果:
db.test.aggregate([
{
"$addFields": {
"allEmails": {
"$reduce": {
"input": {
"$map": {
"input": "$users",
"as": "user",
"in": "$$user.emails"
}
},
"initialValue": [],
"in": { "$concatArrays": ["$$value", "$$this.address"] }
}
}
}
}
])
上述管道最初使用 $map
创建一个二维电子邮件数组来处理对象。显示通过应用表达式
{
"$map": {
"input": "$users",
"as": "user",
"in": "$$user.emails"
}
}
运行一个测试管道,只包含一个包含结果的字段:
db.test.aggregate([
{
"$project": {
"twoDarray": {
"$map": {
"input": "$users",
"as": "user",
"in": "$$user.emails"
}
}
}
}
}
])
将生成2D数组
{
"_id" : ObjectId("589b6132fafb5a09549b46cb"),
"twoDarray" : [
[
{ "address" : "peter@email.com" },
{ "address" : "test2@email.com" }
],
[]
]
}
现在,对这个二维数组进行非规范化
[
[
{ "address" : "peter@email.com" },
{ "address" : "test2@email.com" }
],
[]
]
使用 $reduce
运算符,该运算符将表达式应用于数组中的每个元素,并将它们组合为单个值。在 $concatArrays
运算符的帮助下,您可以连接 $reduce
表达式中的每个元素,以形成最终所需的数组
[
"peter@email.com",
"test2@email.com"
]