Reputation: 4631
I have a database with documents like this:
{
_id: 123,
metrics: [{
_id: ObjectID(…),
name: 'foo',
steps: [1, 2, 3, …],
values: [10, 12, 13, …]
},
{
_id: ObjectID(…),
name: 'bar',
steps: [1, 2, 3, …],
values: [1.2, 1.2, 1.3, …]
},
]
}
Now my objective is to retrieve all documents, but $map
all array entries to their name
attribute, discarding the other fields. I thought I could do it like this:
pipeline = [{'$project': {'metrics': {'$map': {'input': '$metrics', 'in': '$this.name'}]
results = client.db.runs.aggregate(pipeline)
But the result has just None
values for each array entry ({'metrics': [None, None, None, …]}
), as if the requested field name
did not exist. But it does. I've also tried with the id field, to no avail. I can see in inspecting the data that the fields are there. I can't figure out what I'm doing wrong here.
Upvotes: 1
Views: 1969
Reputation: 49975
Inside of $map you can use as
to define temporary variable which will represent single document from your metrics
and then reference that variable in in
part.
db.col.aggregate([{'$project': {'metrics': {'$map': {'input': '$metrics', as: 'metric', 'in': '$$metric.name' } } } }])
or you can directly refer to a temporary variable this
db.col.aggregate([{'$project': {'metrics': {'$map': {'input': '$metrics', 'in': '$$this.name' } } } }])
The thing is that every time you use single dollar sign, you refer to a field that's defined in the document that's being processed in current pipeline stage. Additionally you can use double dollar sign to refer to some variables that can be defined by operators like $map
, $filter
and so on.
You can try your initial code for following document:
{
_id: 123,
this: { name: "x" },
metrics: [{ }, { } ]
}
and you will get an array with two x
values as there are two metrics but every iteration refers to the same this.x
value:
{ "_id" : 123, "metrics" : [ "x", "x" ] }
Upvotes: 1