MongoDB Regex search with language / translation

生来就可爱ヽ(ⅴ<●) 提交于 2020-12-15 03:39:45

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!