I have two related mongo collections. These example documents illustrate their relation:
// "things" collection example document:
{
_id: 1,
categories: [123, 234],
// other fields
}
// "categories" collection example documents:
{
_id: 123,
value: "Category name"
},
{
_id: 234,
value: "Other category name"
}
I've been trying to find a way to map the id numbers in the categories array of a document from things
to the values from the corresponding documents in the categories
collection. Per the above example, you would end up with this document:
{
_id: 1,
categories: [
"Category name",
"Other category name",
],
// other fields
}
My problem is that my current pipeline is overly-complicated and surely performing unnecessary operations, creating potential performance issues. My current pipeline is:
{
_id: 1,
categories: [123, 234],
// other fields
}
$unwind
categories{
_id: 1,
categories: 123,
// other fields
},
{
_id: 1,
categories: 234,
// other fields
}
$lookup
on categories collection matching the new local "categories" field to the foreign "_id"{
_id: 1,
categories: [{ _id: 123, value: "Category name" }],
// other fields
},
{
_id: 1,
categories: [{ _id: 234, value: "Other category name" }],
// other fields
}
$addFields
with { $arrayElemAt: [ "$categories", 0 ] }
to replace the array with the document I wanted in the first place{
_id: 1,
categories: { _id: 123, value: "Category name" },
// other fields
},
{
_id: 1,
categories: { _id: 234, value: "Other category name" },
// other fields
}
$addFields
with { categories: "$categories.value" }
to replace the entire document with just the value field{
_id: 1,
categories: "Category name",
// other fields
},
{
_id: 1,
categories: "Other category name",
// other fields
}
$group
to "undo" the original unwind. I'm using _id: "$_id"
and { $addToSet: "$categories" }
(and maaany other properties in the format <field-name>: { $first: "$<field-name>" }
to re-add all the "other fields"){
_id: 1,
categories: [
"Category name",
"Other category name",
],
// other fields
}
I'm worried I'm missing aggregate functions that are much more efficient and thus creating slow and costly read operations when I use this on a large number of documents in the future but I'm failing to find cleaner solutions. Any nudge in the right direction would be highly appreciated.
per @cmgchess -
This can all be done in two steps:
{
_id: 1,
categories: [123, 234],
// other fields
}
$lookup
(without unwinding){
_id: 1,
categories: [
{
_id: 123,
value: "Category name"
},
{
_id: 234,
value: "Other category name"
}
],
// other fields
}
$set
using $map
// operation:
{
$set: {
categories: {
$map: {
input: "$categories",
as: "category",
in: "$$category.value"
}
}
}
}
// result:
{
_id: 1,
categories: [
"Category name",
"Other category name"
],
// other fields
}
paydirt. :)