1

I have a collection from which I need specific obj e.g. notes.blok2 and notes.curse5 as an object, not as an array

{
  "year":2020,
  "grade":4,
  "seccion":"A",
    "id": 100,
  "name": "pedro",
  "notes":[{"curse":5, 
          "block":1, 
          "score":{ "a1": 5,"a2": 10, "a3": 15} 
          },{"curse":5, 
          "block":2, 
          "score":{ "b1": 10,"b2": 20, "b3": 30} 
          }
   ]
}

My query

notas.find({
"$and":[{"grade":1},{"seccion":"A"},{"year":2020}]},
{"projection":{ "grade":1, "seccion":1,"name":1,"id":1,
"notes":{"$elemMatch":{"block":2,"curse":5}},"notes.score":1} })

It works but returns notes like array

{
  "_id": "55",
  "id": 100,
  "grade": 5,
  "name": "pedro",
  "seccion": "A",
  "notes": [
    {"score": { "b1": 10,"b2": 20, "b3": 30} }
  ]
}

But I NEED LIKE THIS: score at the same level as others and if doesn't exist show empty "score":{}

{
  "year":2020,
  "grade":5,
  "seccion":"A",
    "id": 100,
  "name": "pedro",
  "score":{ "b1": 10,"b2": 20, "b3": 30} 
}
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
Carlos
  • 572
  • 1
  • 5
  • 13

1 Answers1

4

Demo - https://mongoplayground.net/p/XlJqR2DYW1X

You can use aggregation query

db.collection.aggregate([
  {
    $match: { // filter
      "grade": 1,
      "seccion": "A",
      "year": 2020,
      "notes": {
        "$elemMatch": {
          "block": 2,
          "curse": 5
        }
      }
    }
  },
  { $unwind: "$notes" },  //break into individual documents
  {
    $match: { // match query on individual note
      "notes.block": 2,
      "notes.curse": 5
    }
  },
  {
    $project: { // projection
      "grade": 1,
      "seccion": 1,
      "name": 1,
      "id": 1,
      "score": "$notes.score"
    }
  }
])

Update

Demo - https://mongoplayground.net/p/mq5Kue3UG42

Use $filter

db.collection.aggregate([
  {
    $match: {
      "grade": 1,
      "seccion": "A",
      "year": 2020
    }
  },
  {
    $set: {
      "score": {
        "$filter": {
          "input": "$notes",
          "as": "note",
          "cond": {
            $and: [
              {
                $eq: [ "$$note.block",3]
              },
              {
                $eq: [ "$$note.curse", 5 ]
              }
            ]
          }
        }
      }
    }
  },
  {
    $project: {
      // projection
      "grade": 1,
      "seccion": 1,
      "name": 1,
      "id": 1,
      "score": {
        "$first": "$score.score"
      }
    }
  }
])

If you want empty object for score when match not found you can do -

Demo - https://mongoplayground.net/p/dumax58kgrc

  {
    $set: {
      score: {
        $cond: [
          { $size: "$score" }, // check array length
          { $first: "$score" }, // true - take 1st
          { score: {} } // false - set empty object
        ]
      }
    }
  },
Tushar Gupta - curioustushar
  • 58,085
  • 24
  • 103
  • 107