Home > other >  Mongoose Get field with condition
Mongoose Get field with condition

Time:11-10

I have a schema like this:

parentId: Number
name:[ 
       new Schema({
           language: { type: String, enum: ['en-US', 'fr-CA'] },
           text: String,
       },{ _id: false }
       );
     ],
isActive: Boolean
...

and sample data like the following:

{
  parentId:1,
  "name": [
            {"language": "en-US", "text": "Book"},
            {"language": "fr-CA", "text": "livre"}
          ],
   isActive:true
   // and so many other fields
},
{
  parentId:1,
  "name": [
            {"language": "en-US", "text": "Pen"}
          ],
   isActive:true
   // and so many other fields
}

my mongoose searching for French texts:

db.langs.find({
  "name.language":"fr-CA", parentId: 1
})

Q1. How can I return the name in French like this:

{
  parentId:1,
  "name": "livre",
   isActive:true
   // and so many other fields
}

Q2. Is there any possibility in mongoose that I can return the french text and if the french is not there, it returns English?

{
  parentId:1,
  "name": "livre",
   isActive:true
   // and so many other fields
},
{
  parentId:1,
  "name": "pen",
   isActive:true
   // and so many other fields
}

CodePudding user response:

Question 1:

You can use $unwind to deconstruct the array and $match like an object. And least do $addFields to overwrite name field with the desired value (if there are multiple fields is better options than use $project). All this in an aggregation pipeline like this:

db.collection.aggregate([
  {
    "$match": {
      "parentId": 1
    }
  },
  {
    "$unwind": "$name"
  },
  {
    "$match": {
      "name.language": "fr-CA"
    }
  },
  {
    "$addFields": {
      "name": "$name.text"
    }
  }
])

Example here

Question 2:

You can use $facet to create "two ways". One if exists french result and another if not exists. And then check if exists to output one value or another like this:

db.collection.aggregate([
  {
    "$match": {
      "parentId": 1
    }
  },
  {
    "$unwind": "$name"
  },
  {
    "$facet": {
      "french": [
        {
          "$match": {
            "name.language": "fr-CA"
          }
        }
      ],
      "notFrench": [
        {
          "$match": {
            "name.language": "en-US"
          }
        }
      ]
    }
  },
  {
    "$project": {
      "result": {
        "$cond": {
          "if": {
            "$eq": [
              {
                "$size": "$french"
              },
              0
            ]
          },
          "then": "$notFrench",
          "else": "$french"
        }
      }
    }
  }
])

Example here

CodePudding user response:

You can do it with array operations also.

Query1

  • match parent 1
  • fitler to keep only french, and take the text
  • match to have a name (to remove documents that didn't had a french book)

Test code here

aggregate(
[{"$match": {"parentId": {"$eq": 1}}},
  {"$set": 
    {"name": 
      {"$getField": 
        {"field": "text",
          "input": 
          {"$arrayElemAt": 
            [{"$filter": 
                {"input": "$name",
                  "cond": {"$eq": ["$$this.language", "fr-CA"]}}},
              0]}}}}},
  {"$match": {"$expr": {"$eq": [{"$type": "$name"}, "string"]}}}])

Query2

  • match parent 1
  • reduce
    • if value(i found it before) french i keep it
    • else if the current is france i keep this
    • else if the current is us i keep this
    • else value (keep the initial value that is empty {})
  • match to have a name (to remove documents that didn't had a french or us book)

Test code here

aggregate(
[{"$match": {"parentId": {"$eq": 1}}},
  {"$set": 
    {"name": 
      {"$getField": 
        {"field": "text",
          "input": 
          {"$reduce": 
            {"input": "$name",
              "initialValue": {},
              "in": 
              {"$switch": 
                {"branches": 
                  [{"case": {"$eq": ["$$value.language", "fr-CA"]},
                      "then": "$$value"},
                    {"case": {"$eq": ["$$this.language", "fr-CA"]},
                      "then": "$$this"},
                    {"case": {"$eq": ["$$this.language", "en-US"]},
                      "then": "$$this"}],
                  "default": "$$value"}}}}}}}},
  {"$match": {"$expr": {"$eq": [{"$type": "$name"}, "string"]}}}])
  • Related