Ответ 1
Mongo 3.4
$match
- этот этап сохранит весь массив school
и enrolledStudents
, где по крайней мере один встроенный документ соответствует как условию запроса
$group
- Этот этап объединит все массивы school
и enrolledStudents
в массив 2d для каждого _id
в группе.
$project
- Этот этап будет $filter
массивом merge
для соответствия условиям запроса и $map
массива с новыми массивами values
.
$unwind
- Этот этап сгладит массив.
$addFields
и $replaceRoot
- Эти этапы добавят поле id
и продвинут массив values
в начало.
db.collection.aggregate([
{$match : {$or: [{"enrolledStudents.userName" : "michelangelo"} , {"school.name" : "michelangelo"}]}},
{$group: {_id: "$id", merge : {$push:{$setUnion:["$school", "$enrolledStudents"]}}}},
{$project: {
values: {
$map:
{
input: {
$filter: {
input: {"$arrayElemAt":["$merge",0]},
as: "onef",
cond: {
$or: [{
$eq: ["$$onef.userName", "michelangelo"]
}, {
$eq: ["$$onef.name", "michelangelo"]
}]
}
}
},
as: "onem",
in: {
key : { $ifNull: [ "$$onem.userName", "$$onem.name" ] },
code : "$$onem.code"}
}
}
}
},
{$unwind: "$values"},
{$addFields:{"values.id":"$_id"}},
{$replaceRoot: { newRoot:"$values"}}
])
Пример ответа
{ "_id" : 2, "key" : "michelangelo", "code" : 25 }
{ "_id" : 1, "key" : "michelangelo", "code" : "01" }
Mongo <= 3,2
Заменить последние два этапа выше агрегации на $project
, чтобы отформатировать ответ.
{$project: {"_id": 0 , id:"$_id", key:"$values.key", code:"$values.code"}}
Пример ответа
{ "_id" : 2, "key" : "michelangelo", "code" : 25 }
{ "_id" : 1, "key" : "michelangelo", "code" : "01" }
Вы можете использовать $redact
вместо $group
и match
и добавить $project
с помощью $map
, чтобы отформатировать ответ.
$redact
, чтобы пройти уровень документа за раз и выполнить $$DESCEND
и $$PRUNE
по критериям соответствия.
Единственное, что следует отметить, это использование $ifNull
на первом уровне документа для id
, чтобы вы могли $$DESCEND
на уровень встроенного документа для дальнейшей обработки.
db.collection.aggregate([
{
$redact: {
$cond: [{
$or: [{
$eq: ["$userName", "michelangelo"]
}, {
$eq: ["$name", "michelangelo"]
}, {
$ifNull: ["$id", false]
}]
}, "$$DESCEND", "$$PRUNE"]
}
},
{
$project: {
id:1,
values: {
$map:
{
input: {$setUnion:["$school", "$enrolledStudents"]},
as: "onem",
in: {
key : { $ifNull: [ "$$onem.userName", "$$onem.name" ] },
code : "$$onem.code"}
}
}
}
},
{$unwind: "$values"},
{$project: {_id:0,id:"$id", key:"$values.key", code:"$values.code"}}
])