project
Removing vals
Keeping vals
Keeping Subfields
Re-Assign Fields
Making New Fields
Project can be thought of like map in js.
Project shapes a new output in this step of the pipeline.
Project can be re-used in a bunch in pipelines.
Basic project syntax is...
db.solarSystem.aggregate([{$project: {...aggExpressionshere...}}])
Remove values
Project can remove fields from being presented after this pipeline step.
{
fieldName: 0;
}
Keep Values
Project can explicitly keep values to keep after this pipeline step. Once a single filed is identified in this projection field, ALL DESIRED FIELDS must be included in the project stage. Leaving out a field means the field will not appear in the output (access for the '_id' field).
{
fieldname: 1;
}
an example of keeping 1 field, and even removing the _id
field:
db.solarSystem.aggregate([
{
$project: {_id:0, name:1}
}
])
// should return...
{ "name" : "Sun" }
{ "name" : "Mercury" }
{ "name" : "Venus" }
{ "name" : "Earth" }
{ "name" : "Mars" }
{ "name" : "Jupiter" }
{ "name" : "Saturn" }
{ "name" : "Uranus" }
{ "name" : "Neptune" }
NOTE: the _id
field STAYS in project unless explicitly removed.
Keep Subfields
With subfields, the key(s) containing the subfields must be a string with dot notation, parentObj.childKey
:
db.solarSystem.aggregate([{$project: {_id:0, name:1, 'gravity.value': 1}}])
{ "name" : "Sun", "gravity" : { "value" : 274 } }
{ "name" : "Mercury", "gravity" : { "value" : 3.24 } }
{ "name" : "Venus", "gravity" : { "value" : 8.87 } }
{ "name" : "Earth", "gravity" : { "value" : 9.8 } }
{ "name" : "Mars", "gravity" : { "value" : 3.71 } }
{ "name" : "Jupiter", "gravity" : { "value" : 24.79 } }
{ "name" : "Saturn", "gravity" : { "value" : 10.44 } }
{ "name" : "Uranus", "gravity" : { "value" : 8.87 } }
{ "name" : "Neptune", "gravity" : { "value" : 11.15 } }
Reassigning fields
Here, the sub-field of gravity.value
will be re-assigned to value
.
The new field gets declared as a key. The value that the project uses to assign to the new key.
Prefix field vals with $
The aggregation expression must prefix the field (& subfield combo if present, like below) with a $
.
Here, assign the $gravity.value
sub-field from the original doc to a different field in the output called gravity
. Notice that the original field is written with the prefix $
:
db.solarSystem.aggregate([
{
$project: {
_id:0,
name:1,
gravity: '$gravity.value'
}
}
])
// will return...
{ "name" : "Sun", "gravity" : 274 }
{ "name" : "Mercury", "gravity" : 3.24 }
{ "name" : "Venus", "gravity" : 8.87 }
{ "name" : "Earth", "gravity" : 9.8 }
{ "name" : "Mars", "gravity" : 3.71 }
{ "name" : "Jupiter", "gravity" : 24.79 }
{ "name" : "Saturn", "gravity" : 10.44 }
{ "name" : "Uranus", "gravity" : 8.87 }
{ "name" : "Neptune", "gravity" : 11.15 }
Creating an entirely new field
The new name of a reassigned field is arbitrary, and does not need to match the original field names at all. Here, the gravity.value
sub-field gets reassigned to a new surfaceGravity
key/value pair -
db.solarSystem.aggregate([
{$project: {
_id:0,
name:1,
surfaceGravity: '$gravity.value'
}
}])
// will return
{ "name" : "Sun", "surfaceGravity" : 274 }
{ "name" : "Mercury", "surfaceGravity" : 3.24 }
{ "name" : "Venus", "surfaceGravity" : 8.87 }
{ "name" : "Earth", "surfaceGravity" : 9.8 }
{ "name" : "Mars", "surfaceGravity" : 3.71 }
{ "name" : "Jupiter", "surfaceGravity" : 24.79 }
{ "name" : "Saturn", "surfaceGravity" : 10.44 }
{ "name" : "Uranus", "surfaceGravity" : 8.87 }
{ "name" : "Neptune", "surfaceGravity" : 11.15 }
Dabbling with value calculations
Figure out how much I weigh on each planet.
With a weight of 140lb, 140 will be multiplied by a new gravityRatio.
- the gravityRatio will be calculated by
gravity.value
divided by 9.8, earths gravitational force calculation - the gravityRatio will then be multiplied by 140
- this resulting value will be assigned to
myWeight
// vars up front
let EARTH_GRAVITY = 9.8;
let gravityRatio = { $divide: ["$gravity.value",9.8] };
let MY_WEIGHT = 140;
let myWeightOnPlanet = { $multiply: [gravityRatio, MY_WEIGHT] };
// passing 'myWeightOnPlanet' as val of `myWeightHere`
db.solarSystem.aggregate([{
$project: {
_id:0,
planet: "$name",
myWeightHere: myWeightOnPlanet
}
}])
// all-in-one
db.solarSystem.aggregate([
{$project: {
_id:0,
name:1,
myWeight: {
$multiply: [
{
$divide: ["$gravity.value",9.8]
},
140
]
}
}}
])
{ "name" : "Sun", "myWeight" : 3914.285714285714 }
{ "name" : "Mercury", "myWeight" : 46.28571428571429 }
{ "name" : "Venus", "myWeight" : 126.7142857142857 }
{ "name" : "Earth", "myWeight" : 140 }
{ "name" : "Mars", "myWeight" : 53 }
{ "name" : "Jupiter", "myWeight" : 354.1428571428571 }
{ "name" : "Saturn", "myWeight" : 149.14285714285714 }
{ "name" : "Uranus", "myWeight" : 126.7142857142857 }
{ "name" : "Neptune", "myWeight" : 159.28571428571428 }
Pipelines and JS
Pipeline arrays can be saved as vars && inserted into the mongodb query module.
let weightOnPlanetsProjection = [
{
$project: {
_id: 0,
name: 1,
myWeight: {
$multiply: [
{
$divide: ['$gravity.value', 9.8],
},
140,
],
},
},
},
];
// use it something like this...
mongoNodeMod.aggregate(weightOnPlanetsProjection);
Nested objects and arrays
Here, 2 different formats of a user
object in a collection, where the stop
field content is either an obj or an arr ->
{
_id: 1,
user: "1234",
stop: {
title: "book1",
author: "xyz",
page: 32
} }
{
_id: 2,
user: "7890",
stop: [
{
title: "book2",
author: "abc",
page: 5
}, {
title: "book3",
author: "ijk",
page: 100
}
]
}
A single projection will "work" to project only the book titles ->
db.bookmarks.aggregate([{ $project: { 'stop.title': 1 } }]);
// or
db.bookmarks.aggregate([{ $project: { stop: { title: 1 } } }]);