Reputation: 2167
After reworking my data construct, I want to embed a document (or parts of it) from a different collection. Pay your attention to event.tags[]. Currently, there are only their stringified _ids (as plain string, no ObjectId!) stored, but I want to migrate their content, like {tags.name, tags._id}
. I want to update/replace the original event.tags
with the content of tag
-documents.
Collection "events"
db.events.insertMany([{
"_id" : ObjectId("5f6c5b0594911c0b7231643d"),
"title" : "Test Event",
"tags" : [
"5fd8cef2368c625a9d7516cb"
]
},
{
"_id" : ObjectId("5fb3896afc13ae2ed1000000"),
"title" : "Test Event 2",
"tags" : [
"5fd8cef2368c625a9d7516cb",
"5fd8cfb04a4a6063ab4ca4bf",
"5fd8cfb04a4a6063ab4ca4c0"
]
}
]);
Collection "tags"
db.tags.insertMany([{
"_id" : ObjectId("5fd8cef2368c625a9d7516cb"),
"name" : "Foo",
"createdAt" : ISODate("2020-12-15T14:57:54.096Z")
},
{
"_id" : ObjectId("5fd8cfb04a4a6063ab4ca4bf"),
"name" : "Bar",
"createdBy" : "[email protected]",
"createdAt" : ISODate("2020-12-16T14:57:54.096Z")
},
{
"_id" : ObjectId("5fd8cfb04a4a6063ab4ca4c0"),
"name" : "Foobar",
"createdAt" : ISODate("2020-12-17T14:57:54.096Z")
}
]);
I want to achieve to embed some/all fields of collection "tags" matched by "events.tags" <-> "tags._id" as an array of embedded/nested documents. This will be part of a migration script, running over mongoDB API >4.0 thru node.js.
Goal: I want to replace an Array of Strings (see collection events) with certain information of a DIFFERENT collection (see collection tags) and save it back to collection events (migrate process). So I assume, I have to fetch/lookup something from tag
collection and need a mechanism to replace the string (events.tags[x]) with complex objects ({tags._id, tags.name})
{
"_id" : ObjectId("5f6c5b0594911c0b7231643d"),
"title" : "Test Event",
"tags" : [{
"_id" : ObjectId("5fd8cef2368c625a9d7516cb"),
"name" : "Foo",
"createdAt" : ISODate("2020-12-15T14:57:54.096Z")
}]
},
{
"_id" : ObjectId("5fb3896afc13ae2ed1000000"),
"title" : "Test Event 2",
"tags" : [{
"_id" : ObjectId("5fd8cef2368c625a9d7516cb"),
"name" : "Foo"
},
{
"_id" : ObjectId("5fd8cfb04a4a6063ab4ca4bf"),
"name" : "Bar"
},
{
"_id" : ObjectId("5fd8cfb04a4a6063ab4ca4c0"),
"name" : "Foobar"
}]
}
Baby steps
I tried to use the aggregation pipeline and started by matching and lookup their content to replaceWith in the last step. I am not too familiar to solve this via the aggregation pipeline.
db.getCollection('events').aggregate([
{ $match: { tags: { "$exists" : true } } },
{
$lookup:
{
from: "tags",
localField: "tags",
foreignField: "_id",
as: "taags"
}
},
])
Upvotes: 1
Views: 819
Reputation: 36104
You can convert tag's id from string to objectId using $toObjectId
operator, before $lookup
stage,
$addFields
to add new fields and update/format existing fields$map
to iterate loop of tags
array$toObjectId
to convert string objectId to objectId typetags
in as
property of $lookup
stage // $match stage here
{
$addFields: {
tags: {
$map: {
input: "$tags",
in: { $toObjectId: "$$this" }
}
}
}
},
{
$lookup: {
from: "tags",
localField: "tags",
foreignField: "_id",
as: "tags"
}
}
{ $out: "updated_events" }
The second option is to prepare a script to do the manual process,
Upvotes: 1