I have a MongoDB with 3 collections. Here are the 3 collections each with an example of a document it contains:
tag
_id: ObjectId('61b873ec6d075801f7a97e18')
name: 'TestTag'
category: 'A'
computer
_id: ObjectId('6098c5ab615d9e23543d0f6f')
name: 'TestComputer'
category: 'A',
tags: [
ObjectId('61b873ec6d075801f7a97e18')
]
setting
_id: ObjectId('61e56339b528bf009feca149')
name: 'TestSetting'
category: 'A',
tags: [
ObjectId('61b873ec6d075801f7a97e18')
]
As you can see all 3 documents have a category
property and the last 2 documents have a tags
property. The idea is that you can create a tag and tag your computers and settings with the tag, but only within the same category.
Now I'm trying to go from tags
to groups
, so instead of tagging computers and settings, I have created a new group collection that looks like this:
groups
_id: ObjectId('63d2929c2c71e51f8ffcc921')
name: 'TestGroup'
category: 'A'
computers: []
settings: []
I want to "migrate" from tags to groups. So for each tag in my tags collection, I want to create a group with the same name and same category. For each computer and setting that is tagged with that tag, I want to add their _id to the computers and settings arrays in the group.
So if we take the documents I've shown, it would create the following group:
_id: ObjectId('63d26d582c71e51f8ffcc8aa')
name: 'TestTag'
category: 'A'
computers: [
ObjectId('6098c5ab615d9e23543d0f6f')
]
settings: [
ObjectId('61e56339b528bf009feca149')
]
How do I make a query that does this?
CodePudding user response:
First perform $group
to group all tags
by category and name. Then, $lookup
to computer
and setting
to find matching records. Finally, wrangle the $lookup
results a bit and $merge
/$out
to groups
collection.
db.tag.aggregate([
{
$group: {
_id: {
name: "$name",
category: "$category"
},
tags: {
"$addToSet": "$_id"
}
}
},
{
"$lookup": {
"from": "computer",
"localField": "tags",
"foreignField": "tags",
"let": {
c: "$_id.category"
},
"pipeline": [
{
$match: {
$expr: {
$eq: [
"$$c",
"$category"
]
}
}
},
{
$project: {
"_id": 1
}
}
],
"as": "computers"
}
},
{
"$lookup": {
"from": "setting",
"localField": "tags",
"foreignField": "tags",
"let": {
c: "$_id.category"
},
"pipeline": [
{
$match: {
$expr: {
$eq: [
"$$c",
"$category"
]
}
}
},
{
$project: {
"_id": 1
}
}
],
"as": "settings"
}
},
{
$project: {
_id: 0,
name: "$_id.name",
category: "$_id.category",
computers: {
"$map": {
"input": "$computers",
"as": "c",
"in": "$$c._id"
}
},
settings: {
"$map": {
"input": "$settings",
"as": "s",
"in": "$$s._id"
}
}
}
},
{
"$merge": {
"into": "groups",
"on": "_id",
"whenMatched": "merge"
}
}
])