MongoDB Aggregation Query-переименование полей, возвращаемых из встроенных документов
В настоящее время я использую оператор aggregate для возврата документов, содержащих массив вложенных (вложенных) документов. Я хочу переименовать имя поля для массива, а также переименовать имена полей во вложенных документах массива.
Например, для проекции я хочу переименовать массив из "друзей" в "приятелей", а также переименовать поля во встроенном документе из "имя"в " Ник". Могу ли я сделать это в рамках агрегированной операции, и если да, то как?
Вот пример: пример исходного документа:
[
{
_id: ObjectID,
name: 'Matthew',
friends: [
{name: 'Slim', age: '32'},
{name: 'buba', age: '36'}
]
}
]
Вот как должны выглядеть результаты:
[
{
_id: ObjectID,
name: 'Matthew',
buddies: [
{nickName: 'Chris', age: '32'},
{nickName: 'Jim', age: '36'}
]
}
]
Заранее благодарю за помощь.
2 ответа:
Есть несколько подходов к этому, но это во многом зависит от вашей версии MongoDB. Более поздние версии от 2.6 и выше поддерживают
$map
оператор, который вы можете использовать в$project
чтобы делать то, что вы хотите:db.friend.aggregate([ { "$project": { "name": 1, "buddies": { "$map": { "input": "$friends", "as": "el", "in": { "nickName": "$$el.name", "age": "$$el.age" } } } }} ])
В предыдущих версиях вы бы использовали
$unwind
для работы с элементами массива и повторного построения через$group
:db.collection.aggregate([ { "$unwind": "$friends" }, { "$group": { "_id": "$_id", "name": { "$first": "$name" }, "buddies": { "$push": { "nickName": "$friends.name", "age": "$friends.age" } } }} ])
С первой формой быть немного более эффективным, как вы не происходит де-нормализации содержимого массива и создания дополнительных документов в конвейере для обработки.
Я думаю, что понял это следующим агрегированным запросом. Мне было бы интересно, есть ли лучший способ сделать это.
db.friends.aggregate([ { $unwind: '$friends'}, { $project: { _id: 1, name: 1, buddy: { nickName: '$friends.name', age: '$friends.age', } }}, { $group: { _id: '$_id', name: {'$first': '$name'}, buddies: {"$push": "$buddy"} }} ]);
Ниже я опишу ответ каждого оператора ($unwind, $project, $group)
$unwind вернет что-то вроде этого. Он разбивает каждый внедренный документ на свой собственный документ. Итак, где у нас был 1 документ с 2 друзьями sub document, теперь у нас есть два документа. Оба документа будут иметь одинаковые поля id и name, но СУБД friends документ будет отличаться:
{ "_id" : ObjectId("539c80d43cb9fe99d183a5f7"), "name" : "Matthew", "friends" : {"name" : "slim", "age" : "32"} }, { "_id" : : ObjectId("539c80d43cb9fe99d183a5f7"),, "name" : "Matthew", "friends" : {"name" : "buba", "age" : "36"} }
Проект $вернет что-то вроде этого. Здесь я создаю новый встроенный документ под названием buddy и замечаю, что я назначаю "$friends.name к "Нику":
{ "_id" : ObjectId("539c80d43cb9fe99d183a5f7"), "name" : "Matthew", "buddy" : {"nickName" : "slim","age" : "32"} }, { "_id" : : ObjectId("539c80d43cb9fe99d183a5f7"),, "name" : "Matthew", "friends" : {"nickName" : "buba","age" : "36"} }
И тогда $group сделает что-то вроде этого. Здесь я просто группирую все обратно вместе, но устанавливаю имя массива на "buddies":
{ "_id" : ObjectId("539c80d43cb9fe99d183a5f7"), "name" : "Matthew", "buddies" : [ {"nickName" : "slim","age" : "32"}, {"nickName" : "buba","age" : "36"} ] }
Это, кажется, работает, но если бы массив друзей имел дубликаты, этот процесс удалил бы дубликаты. Это может быть решается, если есть уникальный идентификатор для каждого друга.