Home > OS >  How to filter field in array in MongoDB
How to filter field in array in MongoDB

Time:06-07

I have array:

{'_id': ObjectId('7262718c217dda3ad90ef151'), 'SomeText': "aaa", 'items': [{'status': 500, 'x': 1, 'y': None,  'price': 3}, { 'status': 500, 'x': 2, 'y': None,  'price': 4}]}
{'_id': ObjectId('7262718c217dda3ad90ef152'), 'SomeText': "bbb", 'items': [{'status': 300, 'x': 1, 'y': 2,  'price': 7}, { 'status': 500, 'x': 2, 'y': 2,  'price': 5}]}
{'_id': ObjectId('7262718c217dda3ad90ef153'), 'SomeText': "ccc", 'items': [{'status': 300, 'x': 1, 'y': 1,  'price': 8}]}

I need to find documents only those values where x not equal y and only field "SomeText", "х", "y"

Query:

fx = mycol.find({"$expr": {"$ne": ["$items.x", "$items.y"]}},
                   { "_id": 0, "SomeText": 1, "items.x": 1, "items.y": 1, }
                  ).limit(3)
for x in fx:
    print(x)

Returns document with ALL array items in shapes,but I'd like to get the document only with the array that contains x not equal y

{'SomeText': "aaa" 'items': [{'x': 1, 'y': None,}, {'x': 2, 'y': None,}]}
{'SomeText': "bbb", 'items': [{'x': 1, 'y': 2}, {'x': 2, 'y': 2]}

Query:

fx=mycol.aggregate([
    {"$match": {"$expr": {"$ne": ["$items.x", "$items.y"]}}},
    {"$project": {
        "items": {"$filter": {
            "input": '$items',
            "as": 'item',
            "cond":  {"$ne": ["$$item.x", "$$item.y"]}
        }},
        "_id": 0, "SomeText": 1
    }},
    {"$limit" : 5}
])

for x in fx:
    print(x)

Returns document with "status" and "price"

{'SomeText': "aaa", 'items': [{'status': 500, 'x': 1, 'y': None,  'price': 3}, { 'status': 500, 'x': 2, 'y': None,  'price': 4}]}
{'SomeText': "bbb", 'items': [{'status': 300, 'x': 1, 'y': 2,  'price': 7}]}

Can I filter element in array to get result?

{'SomeText': "aaa", 'items': [{'x': 1, 'y': None,}, {'x': 2, 'y': None,}]}
{'SomeText': "bbb", 'items': [{'x': 1, 'y': 2}]}

CodePudding user response:

Just add a $map step to your current query:

db.collection.aggregate([
  {
    $match: {$expr: {$ne: ["$items.x", "$items.y"]}}
  },
  {
    $project: {
      items: {
        $filter: {
          input: "$items",
          as: "item",
          cond: {$ne: ["$$item.x", "$$item.y"]}
        }
      },
      _id: 0,
      SomeText: 1
    }
  },
  {
    $set: {
      items: {
        $map: {
          input: "$items",
          as: "item",
          in: {x: "$$item.x", y: "$$item.y"}
        }
      }
    }
  },
  {
    $limit: 5
  }
])

See how it works on the playground example

  • Related