1

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)
2
  • 1
    (1.) Is the actual schema of the field Language defined as in your code? because main: [Object] would mean array of objects and [Array] would mean array of arrays. (2.) Also, your in your example, secondary should have multiple objects right? currently you have a single objects with duplicate keys. (3.) your post schema has original and target, but your did not mention about user.original and user.target so what is req.user.original and req.user.target? Isn't it supposed to be user.Language? Commented Jul 12, 2020 at 8:21
  • 1. Sorry I printed the console.log. In schema it is defined as Language: [{}] 2. Yes it should be multiple [{name: Japanese, code:jp}, {name:Chinese, code: ch}] 3) I should just have const prefLanguage = req.user.Language. Sorry I'll edit this info Commented Jul 12, 2020 at 8:47

2 Answers 2

2
+50

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] }]
})
Sign up to request clarification or add additional context in comments.

Comments

1

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})

8 Comments

Wouldn't this only list out the post that matches the first set? I could have up to 5 language set. I want to go over all of them.
Then I misunderstood the data structure, is prefLange a list of those objects as i specified in the comment?
yes it's a list of the language set object. Sorry i didn't make this clear
I edited my answer to support an array, the logic is still the similar but we do an $or over the conditions built as there can be multiple.
You can't add a custom sort like that using find, even if you use aggregate you'll still have to manually add a place holder field like kr_sort: 1, jp_sort: 2 and only then you'll be able to sort on that, i'm going to add a simple aggregation that starts with the user to show it.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.