0

Here is one of the document from which i would like get all the child.item ('Toy1','Toy2' etc) in a list.

{
    _id: 'Toy',
    name: 'Toyname',
    child: [
      { item: 'Toy1', isActive: '1', Type: 'New' },
      { item: 'Toy2', isActive: '2', Type: 'Old' }
    ]
  }

I have tried

pipeline = [
   {
      "$match": {
         "_id": "Toy",
         "child.isActive": '1'
      }
   },
   {
      "$unwind":
         "$child"
    },
]
list(DB.Category.aggregate(pipeline))
[{'_id': 'Toy', 'name': 'Toyname', 'child': {'item': 'Toy1', 'isActive': 1, 'Type': 'New'}}, {'_id': 'Toy', 'name': 'Toyname', 'child': {'item': 'Toy2', 'isActive': 2,
'Type': 'Old'}}]

And tried this on dbshell

#> db.Category.find({name:"Toyname",child:{$elemMatch:{Type:"New"} }})
[
  {
    _id: 'Toy',
    name: 'Toyname',
    child: [
      { item: 'Toy1', isActive: '1', Type: 'New' },
      { item: 'Toy2', isActive: '2', Type: 'Old' }
    ]
  }
]

But as you can see it gives me both the items from the array. I am using pymongo 4.0.1.

Expecting a list as o/p which fulfilled match criteria like Type:'New' in $match should return 'Toy1' and isActive:'2' should return 'Toy2'. I hope i am able to put my requirement clearly.

Goldy
  • 17
  • 4
  • 1
    it would be helpful if you post expected result in JSON format. – turivishal Jan 15 '22 at 10:49
  • I want all the items which falls under Type:'new' or isActive:'1' in a list. – Goldy Jan 15 '22 at 11:11
  • Look at the duplicate question, [How to filter array in subdocument with MongoDB](https://stackoverflow.com/questions/15117030/how-to-filter-array-in-subdocument-with-mongodb), you can use $filter expression operator and for c ondition use $and operator. – turivishal Jan 15 '22 at 11:49

1 Answers1

0

You have two options:

  1. Using $elemMatch in a find query. (Be careful because $elemMatch only returns one object from the array)

You can use this query:

db.collection.find({
  "_id": "Toy"
},
{
  "child": {
    "$elemMatch": {
      "isActive": "1"
    }
  }
})

Example [https://mongoplayground.net/p/du7FTnvlW7C]

But also check this example where there are two isActive: "1" and only one is returned.

  1. Using $filter in an aggregate query (also you can use $match,$unwind and $group together but I think using $filter is a better way).

So using aggregate you can try this query:

db.collection.aggregate([
  {
    "$match": {
      "_id": "Toy"
    }
  },
  {
    "$addFields": {
      "child": {
        "$filter": {
          "input": "$child",
          "as": "c",
          "cond": {
            "$eq": ["$$c.isActive","1"]
          }
        }
      }
    }
  }
])

Example here

And using $unwind you need this query which I think is too heavy: two $match, an $unwind and a $group... when you can only use $filter.

J.F.
  • 13,927
  • 9
  • 27
  • 65