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. Whatever the reason, you can use the $project
aggregation pipeline stage to rename a field in your query results.
In some ways, this is comparable to using an alias in SQL, as it doesn’t rename the underlying fields, it simply renames them in the query results.
Example
Suppose we return the contents of a collection like this:
db.employees.find()
Result:
{ "_id" : 2, "name" : "Sarah", "salary" : 128000 } { "_id" : 3, "name" : "Fritz", "salary" : 25000 } { "_id" : 4, "name" : "Chris", "salary" : 45000 } { "_id" : 5, "name" : "Beck", "salary" : 82000 }
Here, we use the find()
method to return the contents of the collection.
In this case, the names of each field are returned in the results.
But what if we wanted the field names to be different? For example, what if we want to replace name
with employee
?
In that case we could use the aggregate()
method to perform a query like this:
db.employees.aggregate([
{ "$project": { "employee": "$name", "salary": 1 }}
])
Result:
{ "_id" : 2, "salary" : 128000, "employee" : "Sarah" } { "_id" : 3, "salary" : 25000, "employee" : "Fritz" } { "_id" : 4, "salary" : 45000, "employee" : "Chris" } { "_id" : 5, "salary" : 82000, "employee" : "Beck" }
Note that MongoDB displays the fields in the order of insertion, which results in the salary
field being presented before the employee
field. If that’s unacceptable, we can always change the query to this:
db.employees.aggregate([
{ "$project": { "employee": "$name", "salary": "$salary" }}
])
Result:
{ "_id" : 2, "employee" : "Sarah", "salary" : 128000 } { "_id" : 3, "employee" : "Fritz", "salary" : 25000 } { "_id" : 4, "employee" : "Chris", "salary" : 45000 } { "_id" : 5, "employee" : "Beck", "salary" : 82000 }
Rename Fields in Embedded Documents
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.find().pretty()
Result:
{ "_id" : 1, "name" : "Wag", "details" : { "type" : "Dog", "weight" : 20, "awards" : { "Florida Dog Awards" : "Top Dog", "New York Marathon" : "Fastest Dog", "Sumo 2020" : "Biggest Dog" } } } { "_id" : 2, "name" : "Fetch", "details" : { "born" : ISODate("2020-06-22T14:00:00Z"), "color" : "Black" } } { "_id" : 3, "name" : "Scratch", "details" : { "eats" : [ "Mouse Porridge", "Bird Soup", "Caviar" ], "type" : "Cat", "born" : ISODate("2020-12-19T14:00:00Z") } }
We can rename fields on the embedded documents like this:
db.pets.aggregate([
{ "$project":
{
"_id": 0,
"Pet": "$name",
"Type": "$details.type",
"Born": "$details.born"
}
}
])
Result:
{ "Pet" : "Wag", "Type" : "Dog" } { "Pet" : "Fetch", "Born" : ISODate("2020-06-22T14:00:00Z") } { "Pet" : "Scratch", "Type" : "Cat", "Born" : ISODate("2020-12-19T14:00:00Z") }
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.
Also note that if a document doesn’t actually have a field that’s specified in the $project
stage, then it will simply be omitted in the resulting document. You can see this in the first document, which omits the Born
field, and the second document, which omits the Type
field.