问题
based on my question before regarding the language text search a have an additional question. MongoDb text search with language support
The search for singular and plural works! Now I also want to find the ingredients if you don't search for the full name. To make this possible I use a regex. The problem is now that this regex is searching over all translations. I do not want to search for all languages. I want only search for the requested language. How is that possible?
Model
{
translation: [
{
language: {
type: String,
required: true
},
name: {
type: String,
required: true
}
}
],
calories: {
"type": Number
},
protein: {
"type": Number
},
carbohydrate: {
"type": Number
},
fat: {
"type": Number
}
}
Data
{
calories: 1,
protein: 2,
carbohydrate: 3,
fat: 4,
translation: [
{
_id: ObjectId('5fba87d13ad6404108191670'),
language: 'german',
name: 'gurke'
},
{
_id: ObjectId('5fba87d13ad6404108191671'),
language: 'english',
name: 'cucumber'
},
{
_id: ObjectId('5fba87d13ad6404108191672'),
language: 'spanish',
name: 'pepino'
}
]
}
// ----
{
calories: 4,
protein: 3,
carbohydrate: 2,
fat: 1,
translation: [
{
_id: ObjectId('5fba87d13ad6404108191674'),
language: 'german',
name: 'huhn'
},
{
_id: ObjectId('5fba87d13ad6404108191675'),
language: 'english',
name: 'chicken'
},
{
_id: ObjectId('5fba87d13ad6404108191676'),
language: 'spanish',
name: 'pollo'
}
]
}
Code
import express from 'express';
const escapeRegex = (text) => {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
};
const language = {
de: "german",
en: "english",
es: "spanish",
}
const Router = express.Router
module.exports = Router({mergeParams: true})
.get('/foods', async (req, res, next) => {
try {
const search = escapeRegex(req.query.search);
let found = await req.db.Foods
.find({$text:{$search: search, $language: req.language}})
.exec();
// response with a accurate result
if(found.length > 0) {
res.status(200).json(found);
return;
}
// expensive search
found = await req.db.Foods
.find(
{
"translation.language": language[req.language] || "de" , // has no effect
"translation.name": new RegExp(`${search}`, "ig")
}
)
.limit(20)
.exec();
res.status(200).json(found);
} catch(error) {
next(error);
}
})
Let's take the chicken as an example again. If i search for ck
in english I want to get the chicken as result. But if I use german as language, I don't want the chicken to show up. In my current solution the chicken is also showing when I search in german.
expect no result
GET http://localhost:8080/api/foods?search=ck
Accept-Language: de
expect show me the chicken
GET http://localhost:8080/api/foods?search=ck
Accept-Language: en
I have all translations in one array, so my language filter has no effect. Is there a solution where I can exclude different languages? I am looking for something where the language and the corresponding name in an array entry matches. Current match one entry in language and the other entry in name.
Thank you for your help!
The only solution I can think of at the moment is to put each language into an additional column. Then you can run the regex in a different column depending on the language. The disadvantage is that you have to create the ingredients redundantly and to create multiple indexes. But this solution is not good
Model
{
translation: [{
language: { type: String, required: true },
name: { type: String, required: true}
}],
name_english: { type: String },
name_german: { type: String },
name_spanish: { type: String },
}
Index
foodSchema.index( { "translation.name": "text", "name_english": "text", "name_german": "text", "name_spanish": "text"}, { default_language: "none" } )
来源:https://stackoverflow.com/questions/64971224/mongodb-regex-search-with-language-translation