Подтвердить что ты не робот

Как переименовать поля при выполнении поиска/проекции в MongoDB?

Можно ли переименовать имя полей, возвращаемых в запросе поиска? Я хотел бы использовать что-то вроде $rename, однако мне не хотелось бы менять документы, к которым я обращаюсь. Я хочу просто получить их по-другому, что работает как SELECT COORINATES AS COORDS в SQL.

Что я делаю сейчас:

db.tweets.findOne({}, {'level1.level2.coordinates': 1, _id:0})
{'level1': {'level2': {'coordinates': [10, 20]}}}

То, что я хотел бы вернуть, - это: {'coords': [10, 20]}

4b9b3361

Ответ 1

Таким образом, в основном используется .aggregate() вместо .find():

db.tweets.aggregate([
    { "$project": {
        "_id": 0,
        "coords": "$level1.level2.coordinates"
    }}
])

И это дает вам результат, который вы хотите.

MongoDB 2.6 и более поздние версии возвращают "курсор", как это делает find.

Смотрите $project и другие операторы структуры агрегации для более подробной информации.


В большинстве случаев вы должны просто переименовать поля, как возвращено из .find() при обработке курсора. Для JavaScript в качестве примера вы можете использовать .map() для этого.

Из оболочки:

db.tweets.find({},{'level1.level2.coordinates': 1, _id:0}).map( doc => {
  doc.coords = doc['level1']['level2'].coordinates;
  delete doc['level1'];
  return doc;
})

Или более встроенный:

db.tweets.find({},{'level1.level2.coordinates': 1, _id:0}).map( doc => 
  ({ coords: doc['level1']['level2'].coordinates })
)

Это позволяет избежать каких-либо дополнительных накладных расходов на сервере и должно использоваться в тех случаях, когда дополнительные накладные расходы обработки перевешивают выигрыш от фактического уменьшения размера извлекаемых данных. В этом случае (и в большинстве случаев) было бы минимальным и, следовательно, лучше повторно обработать результат курсора для реструктуризации.

Ответ 2

Как упомянул @Neil Lunn, этого можно достичь с помощью конвейера агрегации:

А начиная с Mongo 4.2, оператор агрегации $replaceWith можно использовать для замены документа вложенным документом:

// { level1: { level2: { coordinates: [10, 20] }, b: 4 }, a: 3 }
db.collection.aggregate(
  { $replaceWith: { coords: "$level1.level2.coordinates" } }
)
// { "coords" : [ 10, 20 ] }

Поскольку вы упоминаете findOne, вы также можете ограничить количество полученных документов до 1 как таковое:

db.collection.aggregate([
  { $replaceWith: { coords: "$level1.level2.coordinates" } },
  { $limit: 1 }
])

До Mongo 4.2 и запуска Mongo 3.4 можно использовать $replaceRoot вместо $replaceWith:

db.collection.aggregate(
  { $replaceRoot: { newRoot: { coords: "$level1.level2.coordinates" } } }
)