Given these excerpt collections:
Translation Collection
[
{
"_id": "id01_name",
"text": "Item's Name"
},
{
"_id": "id01_desc",
"text": "Item's lore description"
},
{
"_id": "sk_id",
"text": "Item's skill description"
},
]
Item Collection
[
{
"_id": "id01",
"name": "id01_name",
"lore_description": "id01_desc",
"skill": {
"description": "sk_id01",
}
}
]
Question:
Using only mongodb driver (NO Mongo ODM, like mongoose, iridium, etc), what is the best approach for (i18n) Internationalization (with fallback) on MongoDB when translation is in another Collection?
MongoDB's aggregate
Approach
Currently, I'm using aggregate
with $lookup
to do these kind of queries.
db.artifact.aggregate([
{
$lookup: { // get the name's data from the english translation
from: "text_en",
localField: "name",
foreignField: "_id",
as: "name"
},
},
{
$unwind: "$name" //unwind because the lookup made name become an array with _id and text
},
{
$addFields: {
name: "$name.text" //rewrite name (currently an obj) into the translation string
}
},
(...etc)
Problem is, I need these 3 steps on every single key I need to translate. On a big document, looks a bit too much, and every $lookup
feels like the response time increases bit by bit.
This also doesn't have fallback cases, in case key is not available in said language, e.g., try $lookup
on id01_name
in the Spanish collection but the collection doesn't have it, so a fallback would be get from English collection.
Here a working example of the example above: https://mongoplayground.net/p/umuPQYriFRe
Manual aggregation Approach
I also thought in doing in phases, that is,
item.find()
to get item data;translation_english.find({ $in: [ (...listofkeys) ]})
to get all necessary english keystranslation_{otherlang}.find({ $in: [ (...listofkeys) ]})
to get all necessary other language keys- manually transform the two translation arrays into two objects (with
cursor.forEach()
), merge withObject.assign({},eng,otherlang)
- handpicking each key and assigning to the item object
This method covers the fallback, but it's bloated/very verbose.
On a test with both attempts, lookup took 310ms and the manual took 500ms to complete, that for one lookup. But manual has fallback (aka queries 3 collections; item, lang_en, lang_{foreign}
). If language key does not exist in foreign, it'll pick the en (it's assumed eng will never miss a key).
While lookup fails to return a document when the lookup on foreign lang fails.