Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I rename fields when performing search/projection in MongoDB?

Is it possible to rename the name of fields returned in a find query? I would like to use something like $rename, however I wouldn't like to change the documents I'm accessing. I want just to retrieve them differently, something that works like SELECT COORINATES AS COORDS in SQL.

What I do now:

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

What I would like to be returned is: {'coords': [10, 20]}

like image 347
themiurgo Avatar asked May 21 '14 13:05

themiurgo


People also ask

How do I rename a field in MongoDB aggregate?

You can use the same method to rename fields in embedded documents. In this case, use dot-notation to refer to the field that you want to rename. In this case I didn't select all fields in the embedded documents, but you get the idea. I also used "_id": 0 to omit the _id field.

Can we rename _id in MongoDB?

You cannot update it but you can save a new id and remove the old id.

How do I change the key name in MongoDB?

MongoDB provides different types of field update operators to update the values of the fields of the documents and $rename operator is one of them. This operator is used to update the names of the fields with new names. The new name of the field should be different from the existing name of the field.

How to select fields from a query in MongoDB?

Summary: in this tutorial, you’ll how to use the MongoDB projection that allows you to select fields to return from a query In MongoDB, projection simply means selecting fields to return from a query. By default, the find () and findOne () methods return all fields in matching documents. Most of the time you don’t need data from all the fields.

Why are my MongoDB field names so inconsistent?

Sometimes when you query a collection in MongoDB, you might not be happy with the field names. By default, the field names are simply a reflection of the field names in the actual documents. Perhaps the field names are inconsistent, or there’s a typo.

How do I rename the fields returned from find()?

For most cases you should simply rename the fields as returned from .find () when processing the cursor. For JavaScript as an example, you can use .map () to do this. db.tweets.find ( {}, {'level1.level2.coordinates': 1, _id:0}).map ( doc => { doc.coords = doc ['level1'] ['level2'].coordinates; delete doc ['level1']; return doc; })

How to rename a field in an embedded document?

You can use the same method to rename fields in embedded documents. In this case, use dot-notation to refer to the field that you want to rename. Suppose we run the following query against a pets collection: db.pets.aggregate ( [ { "$project": { "_id": 0, "Pet": "$name", "Type": "$details.type", "Born": "$details.born" } } ])


3 Answers

So basically using .aggregate() instead of .find():

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

And that gives you the result that you want.

MongoDB 2.6 and above versions return a "cursor" just like find does.

See $project and other aggregation framework operators for more details.


For most cases you should simply rename the fields as returned from .find() when processing the cursor. For JavaScript as an example, you can use .map() to do this.

From the shell:

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

Or more inline:

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

This avoids any additional overhead on the server and should be used in such cases where the additional processing overhead would outweigh the gain of actual reduction in size of the data retrieved. In this case ( and most ) it would be minimal and therefore better to re-process the cursor result to restructure.

like image 121
Neil Lunn Avatar answered Oct 21 '22 18:10

Neil Lunn


As mentioned by @Neil Lunn this can be achieved with an aggregation pipeline:

And starting Mongo 4.2, the $replaceWith aggregation operator can be used to replace a document by a sub-document:

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

Since you mention findOne, you can also limit the number of resulting documents to 1 as such:

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

Prior to Mongo 4.2 and starting Mongo 3.4, $replaceRoot can be used in place of $replaceWith:

db.collection.aggregate(
  { $replaceRoot: { newRoot: { coords: "$level1.level2.coordinates" } } }
)
like image 43
Xavier Guihot Avatar answered Oct 21 '22 17:10

Xavier Guihot


As we know, in general, $project stage takes the field names and specifies 1 or 0/true or false to include the fields in the output or not, we also can specify the value against a field instead of true or false to rename the field. Below is the syntax

    db.test_collection.aggregate([
        {$group: {
            _id: '$field_to_group',
            totalCount: {$sum: 1}
        }},
        {$project: {
            _id: false,
            renamed_field: '$_id',    // here assigning a value instead of 0 or 1 / true or false effectively renames the field.
            totalCount: true
        }}
    ])
like image 4
Abhilash Avatar answered Oct 21 '22 17:10

Abhilash