У меня есть совокупный запрос, который извлекает результат из 3 коллекций.
Я использую mongoDb 3.4
Один образец документа из результата.
{
"_id" : ObjectId("5ba1717ee4b00ce08ca47cfa"),
"name" : "captain jack",
"email" : "[email protected]",
"mobile" : "9000000023",
"status" : "verified",
"courses" : [
{
"_id" : "13",
"name" : "Course (03)"
},{
"_id" : "12",
"name" : "Course (03)"
}
],
"examCompleted" : false,
"login" : "5ba1717ee4b00fe08ca47cfa",
"partnerMetaInfo" : {
"_id" : ObjectId("5ba1717ee4b00fe08ca47cfa"),
"costCode" : "5761",
"hub" : "CALCUTTA",
"location" : "Kolkata"
}
}
Я пытаюсь установить partnerMetaInfo
на корневом уровне.
Я также не могу фильтровать курсы ._id с помощью $ match на _id == 13
Это мой сводный запрос:
db.getCollection("mainCollection").aggregate([
{
//Join two collection
$lookup:{
from: "Details",
localField: "username",
foreignField: "login",
as: "partnerData"
}
},{
//Limit fields
$project:{
"email":1,
"name":1,
"mobile":1,
"status" : 1,
"courses":"$partnerData.courses",
"examScore" : "$partnerData.examScore",
"examCompleted" : "$partnerData.examCompleted",
"login":"$partnerData.login"
}
},
{
//Join third collection
$lookup:{
from: "PartnerMetaInfo",
localField: "login",
foreignField: "partnerId",
as: "partnerMetaInfo"
}
},
//Remove from partnerData array and place at root level.
{
$unwind:
{
path: '$courses',
preserveNullAndEmptyArrays: true
}
},{
$unwind:
{
path: '$examScore',
preserveNullAndEmptyArrays: true
}
},{
$unwind:
{
path: '$examCompleted',
preserveNullAndEmptyArrays: true
}
},{
$unwind:
{
path: '$login',
preserveNullAndEmptyArrays: true
}
},//Bring $partnerMetaInfo array to root level.
{
$unwind:
{
path: '$partnerMetaInfo',
preserveNullAndEmptyArrays: true
}
},{
$limit:10
}
];
partnerMetaInfo после того, как $ unwind заканчивается как объект. Я хочу сгладить его и довести до корневого уровня.
Может ли кто-нибудь помочь мне с этим?
Если все, что вы хотите получить в результате, - это содержимое вашего поля partnerMetaInfo
, вы можете просто добавить этап $ replaceRoot в конце конвейера следующим образом:
{
$replaceRoot: { "newRoot": { $ifNull: [ "$partnerMetaInfo", {} ] } }
}
В противном случае, если вы хотите просто переместить поля внутри поля partnerMetaInfo
в корень, вы должны использовать $ addFields:
{
$addFields: {
"partnerMetaInfoId" : "$partnerMetaInfo._id",
"costCode" : "$partnerMetaInfo.costCode",
"hub" : "$partnerMetaInfo.hub",
"location" : "$partnerMetaInfo.location"
}
}
Если у вас есть динамическое количество полей или вы не хотите жестко кодировать имена полей, вы можете использовать следующую логику:
{
$replaceRoot: { // merge fields of and move them all the way up
"newRoot": { $mergeObjects: [ "$$ROOT", "$partnerMetaInfo" ] }
}
}, {
$project: { // remove the "partnerMetaInfo" field
"partnerMetaInfo": 0
}
}
Я пробовал это, но появляется сообщение об ошибке ''newRoot' expression must evaluate to an object, but resulting value was: MISSING. Type of resulting value: 'missing'.
. Я уже использовал $ unwind, поэтому массив преобразуется в объект. Теперь мне нужно сгладить объект и поместить его в корень. Надеюсь, я понял.
Что ж, если я удалю preserveNullAndEmptyArrays
, то документ исчезнет из результата, если partnerMetaInfo будет пустым или нулевым.
Попробуйте обновленную версию, указанную выше. Здесь еще раннее утро, а я еще немного слепой. ;)
Не работает. возвращает много пустых объектов и изменяет структуру документов. :(
@HardikShah: да, partnerMetaInfo уже находится на корневом уровне как объект. Но мне нужно удалить поля в объекте и разместить его на корневом уровне. Ваше решение не сработало. В любом случае спасибо.
отсутствие ключей внутри metaInfo будет динамическим. В том смысле, что у некоторого объекта будет 5 ключей, некоторым может потребоваться 10 полей. Так что я не могу жестко запрограммировать. Есть ли сокращение для всех ключей, пример *
Если я правильно понял,
partnerMetaInfo
уже находится на корневом уровне, тогда вы можете добавить еще один проект в конце$project:{ partnerMetaInfo: 1}
, и он вернет толькоpartnerMetaInfo
вместе с_id
.