简体   繁体   中英

MongoDB query on multiple array of objects

Say I have a mongoSchema of user with the following field

googleId: String,
name: String,
Language : [{}],

User can initially specify an array of language-set [up to 5] on their profile page.

For example, user can have 2 language set as below:

Language:

[main: {name: English, code: ko}, secondary: [{name:Japanese, code: jp}, {name:Chinese, code: en}]], 

[main: {name: Korean, code: ko}, secondary: [{name:Japanese, code: jp}, {name:English, code: en}]

From this information, I want to render out only the post that matches the following preference.

For example post with English to Japanese , English to Chinese (from first language set)

as well as post with Korean to Japanese , Korean to English (from second language set)

My post schema has

    postName: String
    original: {},
    target: {},

For example,

postName: 'Korean to Japanese Post'
original: {name: Korean, code: ko}
target: {name: Japanese, code jp}

What should I put inside the curly brackets to fetch the posts with specified language set

const prefLang = req.user.Language
const post = await Post.find({ some query using prefLang to check over matching original and target })
res.send(translations)

The query object should look like this for your example

{
  $or: [
    {
      original: { name: "English", code: "en" },
      target: {
        $in: [{ name: "Japanese", code: "jp" }, { name: "Chinese", code: "cn" }]
      }
    },
    {
      original: { name: "Korean", code: "ko" },
      target: {
        $in: [{ name: "Japanese", code: "jp" }, { name: "English", code: "en" }]
      }
    }
  ]
}

So you will have to construct the condition from prefLang like this

const query = {
  $or: perfLang.map(lang => ({
    original: lang.main,
    target: { $in: lang.secondary }
  }))
}

const post = await Post.find(query)

Tip:

If the language objects have a strict schema, you can define them like this

const LanguageSchema = new mongoose.Schema({
  name: String,
  code: String
}, {
  _id: false
})

const UserSchema = new mongoose.Schema({
  //...
  googleId: String,
  name: String,
  Language: [{ main: LanguageSchema, secondary: [LanguageSchema] }]
})

Sounds like the usage of basic boolean logic would suffice:

const prefLang = req.user.Language;

let conditions = [];

prefLang.forEach((langObj) => {
    let tragetLangs = langObj.secondary.map(lang => lang.code);
    conditions.push({
        $and: [
            {
                "original.code": langObj.main.code,
            },
            {
                "target.code": {$in: tragetLangs}
            }
        ]
    })
})

// you should check conditions !== empty array.
const post = await Post.find({$or: conditions})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM