The project I am working on is a trilingual dictionary. I have a database of words, and each word contains (among other things) an array of spelling variations and an array of objects representing definitions in all three languages, as seen below:
// Word object
{
variants: ["chuyuchik", "chuyuchiikk"],
definitions: [
{
en: {
translation: "English definition",
example: "English example",
},
es: {
translation: "Spanish definition",
example: "Spanish example",
},
tz: {
example: "Tz'utujil example",
},
},
}
I'm trying to implement a feature where new words can be added to the database but if a word is a duplicate (based on what the variants
array contains) they are merged. My problem occurs when trying to merge the definitions
arrays in the two words. The flow I'm trying to achieve is as follows:
translation
in the new word is a duplicate of an existing translation
in the original word (in the same language), but the new word has an example attached to it then that example should be put into the merged word in its respective place.translation
, that translation
and its example
(if it exists) should be appended to the definitions array.I've tried a bunch of different ways to achieve this - maps, loops, flattening out the objects - I can't seem to wrap my mind around it. Any suggestions?
Here's an example of what the before and after should be:
// Original definitions in word
const oldDefs = [{
en: {
translation: "EN 1",
example: "ENGLISH EX 1",
},
es: {
translation: "ES 1",
example: "SPANISH EX 1",
},
tz: {
example: "TZ EXAMPLE 1",
},
}, {
en: {
translation: "EN 2",
example: "",
},
es: {
translation: "",
example: "",
},
tz: {
example: "",
},
}]
// The definitions to merge into the original
const newDefs = [{
en: {
translation: "EN 2",
example: "ENGLISH EX 2",
},
es: {
translation: "ES 2",
example: "SPANISH EX 2",
},
tz: {
example: "TZ EXAMPLE 1",
},
}]
// What the output should be
const output = [{
en: {
translation: "EN 1",
example: "ENGLISH EX 1",
},
es: {
translation: "ES 1",
example: "SPANISH EX 1",
},
tz: {
example: "TZ EXAMPLE 1",
},
}, {
en: {
translation: "EN 2",
example: "ENGLISH EX 2",
},
es: {
translation: "ES 2",
example: "SPANISH EX 2",
},
tz: {
example: "",
},
}]
Create a copy of the old definitions array (i.e., res
).
Iterate over each new definition (b
) in newDefs
.
For each new definition, check if it matches any existing definition (a
) in res
.
lang
in the new definition does not exist in the old definition, initialize it.If the translation in the new definition does not exist in the old one, add the new translation and example to the old one.
If no match is found for a new definition after checking all existing definitions, add the new one to res
.
Use a Set()
to keep track of visited examples for each language.
If an example is already visited, set the duplicate example to an empty string.
function _merge(A, B) {
const res = [...A];
B.forEach((b) => {
let flag = false;
res.forEach((a) => {
Object.keys(b).forEach((lang) => {
if (!a[lang]) {
a[lang] = {
translation: "",
example: "",
};
}
if (
b[lang].translation &&
b[lang].translation === a[lang].translation
) {
if (b[lang].example && !a[lang].example) {
a[lang].example = b[lang].example;
}
flag = true;
} else if (b[lang].translation && !a[lang].translation) {
a[lang].translation = b[lang].translation;
a[lang].example = b[lang].example || "";
flag = true;
}
});
});
if (!flag) {
res.push({ ...b });
}
});
res.forEach((def) => {
Object.keys(def).forEach((lang) => {
const vis = new Set();
res.forEach((d) => {
if (d[lang] && d[lang].example) {
if (vis.has(d[lang].example)) {
d[lang].example = "";
} else {
vis.add(d[lang].example);
}
}
});
});
});
return res;
}
const oldDefs = [
{
en: {
translation: "EN 1",
example: "ENGLISH EX 1",
},
es: {
translation: "ES 1",
example: "SPANISH EX 1",
},
tz: {
example: "TZ EXAMPLE 1",
},
},
{
en: {
translation: "EN 2",
example: "",
},
es: {
translation: "",
example: "",
},
tz: {
example: "",
},
},
];
const newDefs = [
{
en: {
translation: "EN 2",
example: "ENGLISH EX 2",
},
es: {
translation: "ES 2",
example: "SPANISH EX 2",
},
tz: {
example: "TZ EXAMPLE 1",
},
},
];
console.log(_merge(oldDefs, newDefs));