Given this collection of courses, there is a list of subjects that are composed of objects. Is it possible to create an aggregation to create a new field newSubjects
that maps all subjects by their ids? For example, given this collection how to transform the subjects
entries from :
[
{
_id: ObjectId("623e2f0cb242ee9367eb3c9f"),
subjects: [ { id: '1', name: 'math' }, { id: '2', name: 'physics' } ]
},
{
_id: ObjectId("623e2f17b242ee9367eb3ca0"),
subjects: [ { id: '1', name: 'math' }, { id: '3', name: 'biology' } ]
}
]
into:
{
newSubjects: { '1': { id: '1', name: 'math' }, '2': { id: '2', name: 'physics' } }
}
{
newSubjects: { '1': { id: '1', name: 'math' }, '3': { id: '3', name: 'biology' } }
}
Using JavaScript I could do with this expression:
db.courses.find().forEach(x => print({"newSubjects": Object.fromEntries(new Map(x.subjects.map(s => [s.id, s])))}))
I'm trying to figure out an aggregation to accomplish this but haven't succeeded with $addField
and $map
yet.
CodePudding user response:
You can try this query:
Only need one aggregate stage to compound the result you want. In this stage you can use a $map
to iterate for every value and return a new one. This new one will have k
and v
fields.
k
field will be the object key (1, 2, 3...)v
field will be the value field (the object with {id:..., name:...})
And wrapped by $arrayToObject
to translate k
and v
to the desired object.
db.collection.aggregate([
{
"$project": {
"_id": 0,
"newSubjects": {
"$arrayToObject": {
"$map": {
"input": "$$ROOT.subjects",
"in": {
"k": "$$this.id",
"v": {
"id": "$$this.id",
"name": "$$this.name"
}
}
}
}
}
}
}
])
Example here
CodePudding user response:
Another option:
db.collection.aggregate([
{
"$project": {
"newSubjects": {
"$arrayToObject": {
"$map": {
"input": "$subjects",
"as": "s",
"in": {
k: "$$s.id",
v: "$$s"
}
}
}
}
}
}
])
Explained:
Map the array with the necessary k,v suitable for arrayToObject to be projected as newSubjects