web-dev-qa-db-fra.com

Comment renommer des champs lors d'une recherche / projection dans MongoDB?

Est-il possible de renommer le nom des champs retournés dans une requête de recherche? Je voudrais utiliser quelque chose comme $rename, mais je ne voudrais pas modifier les documents auxquels j'accède. Je veux juste les récupérer différemment, quelque chose qui fonctionne comme SELECT COORINATES AS COORDS en SQL.

Ce que je fais maintenant:

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

Ce que je voudrais être retourné est: {'coords': [10, 20]}

36
themiurgo

Donc, en gros, utilisez .aggregate() au lieu de (.find() :

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

Et cela vous donne le résultat que vous souhaitez.

MongoDB 2.6 et versions supérieures renvoient un "curseur" comme le fait find.

Voir $project et autres opérateurs de structure d'agrégation pour plus de détails.


Dans la plupart des cas, vous devez simplement renommer les champs tels qu'ils sont renvoyés par .find() lors du traitement du curseur. Pour JavaScript comme exemple, vous pouvez utiliser .map() pour ce faire.

De la coque:

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

Ou plus en ligne:

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

Cela évite toute surcharge supplémentaire sur le serveur et doit être utilisé dans les cas où la surcharge de traitement supplémentaire serait supérieure au gain de réduction réelle de la taille des données récupérées. Dans ce cas (et la plupart), il serait minime et donc préférable de retraiter le résultat du curseur pour le restructurer.

45
Neil Lunn

Comme mentionné par @Neil Lunn, cela peut être réalisé avec un pipeline d'agrégation:

Et à partir de Mongo 4.2, les $replaceWith L'opérateur d'agrégation peut être utilisé pour remplacer un document par un sous-document:

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

Puisque vous mentionnez findOne, vous pouvez également limiter le nombre de documents résultants à 1 en tant que tel:

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

Antérieur à Mongo 4.2 et démarrage Mongo 3.4, $replaceRoot peut être utilisé à la place de $replaceWith:

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