Home > Net >  MongoDB Conditional Projection based on existence of query of subdocument in Array
MongoDB Conditional Projection based on existence of query of subdocument in Array

Time:09-29

I have a schema in which properties can have respective "override" documents stored in an Array("overrides")

E.g.

`{
    foo:'original foo',
    overrides: [
        {property:'foo', value:'foo override'},
        {property:'bar', value:'bar override'},
    ]
}`

I want to project a field for the override value if it exists, otherwise, the original property.

So something like this

project: { overrideOrOriginal: {$cond: fooOverrideExists ? fooOverrideValue : originalFooValue }

So in this example, I would expect overrideOrOriginal to equal 'foo override' . If - {property:'foo', value:'foo override'} subDoc didn't exist in the overrides array (or if overrides array itself didn't even exist)...then I'd expect overrideOrOriginal = 'original foo'

How can I do this? I was thinking I'd need $exists in tandem with $cond. But the complication here is that I'm searching for a subDoc in an Array based on a query

Thanks!

CodePudding user response:

  • $in to check "foo" is in overrides.property array
  • $indexOfArray to get index of array element in overrides.property array
  • $arrayElemAt to get element by specific index return from above operator
let fooOverrideExists = "foo";
db.collection.find({},
{
  overrideOrOriginal: {
    $cond: [
      { $in: [fooOverrideExists, "$overrides.property"] },
      {
        $arrayElemAt: [
          "$overrides.value",
          { $indexOfArray: ["$overrides.property", fooOverrideExists] }
        ]
      },
      "$foo"
    ]
  }
})

Playground

CodePudding user response:

Query

  • find the property , key-value(kv) (it works for all property names)
    (assumes your schema with only string value the value of that property)
  • checks if that it exists in the overrides array
  • if it exists, takes the value from the array
  • else keeps the original

*checks also cases where override doesnt exists, or its empty array, or property doesn't exist

In case you already know the "foo" use this and ignore the first big part.

Test code here

db.collection.aggregate([
  {
    "$set": {
      "kv": {
        "$arrayElemAt": [
          {
            "$filter": {
              "input": {
                "$objectToArray": "$$ROOT"
              },
              "cond": {
                "$eq": [
                  {
                    "$type": "$$this.v"
                  },
                  "string"
                ]
              }
            }
          },
          0
        ]
      }
    }
  },
  {
    "$set": {
      "index": {
        "$indexOfArray": [
          "$overrides.property",
          "$kv.k"
        ]
      }
    }
  },
  {
    "$project": {
      "_id": 0,
      "overrideOrOriginal": {
        "$cond": [
          {
            "$or": [
              {
                "$eq": [
                  "$index",
                  -1
                ]
              },
              {
                "$not": [
                  "$overrides"
                ]
              }
            ]
          },
          "$kv.v",
          {
            "$arrayElemAt": [
              "$overrides.value",
              "$index"
            ]
          }
        ]
      }
    }
  }
])
  • Related