1

I have a simple datastructure in mongodb:

{
  _id: ObjectID,
 name: 'Name',
 birthday: '25.05.2001'
 items: [
          {
             _id: ObjectID,
             name: 'ItemName',
             info: 'ItemInfo',
           },
           {
             _id: ObjectID,
             name: 'ItemName',
             info: 'ItemInfo',
           }
        ]
}

Now i want a query, that takes a ObjectID (_id) of an item as criteria and gives me back the object with all items in the array AND projects a new field "selected" with value true or false into a field in the result of each array item:

I tried that with this query:

 { $unwind: '$items' },
 {
    $project: {
       selected: {
          $cond: { if: { 'items._id': itemObjectID }, then: true, else: false },
      },
    },
  },    

but MongoDB gives me back an error:

MongoError: FieldPath field names may not contain '.'.

Have no clue why its not working, any help or ideas? Thank you very much!

0

2 Answers 2

1

What you are missing here is $eq aggregation operator which checks the condition for the equality.

You can try below aggregation here if you want to check for ObjectId then you need to put mongoose.Types.ObjectId(_id)

db.collection.aggregate([
  { "$unwind": "$items" },
  { "$addFields": {
    "items.selected": {
      "$eq": [
        1111,
        "$items._id"
      ]
    }
  }},
  { "$group": {
    "_id": "$_id",
    "name": { "$first": "$name" },
    "items": {
      "$push": {
        "_id": "$items._id",
        "selected": "$items.selected"
      }
    }
  }}
])

Will give following output

[
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "items": [
      {
        "_id": 1111,
        "selected": true
      },
      {
        "_id": 2222,
        "selected": false
      }
    ],
    "name": "Name"
  }
]

You can check it here

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! I found my solution with your help. I posted it as an answer to my own question because of the large code part...thx
0

@Ashish: Thank you very much for your help! Your answer helped me to build the right query for me:

  db.collection.aggregate([
  {
    $unwind: "$items"
  },
  {
    $project: {
      "items.name": 0,
      "birthday": 0
    }
  },
  {
    "$addFields": {
      "items.selected": {
        "$eq": [
          1111,
          "$items._id"
        ]
      }
    }
  },
  {
    $group: {
      _id: "$_id",
      "name": {
        "$first": "$name"
      },
      items: {
        $push: "$items"
      }
    }
  },
  {
    $match: {
      "items._id": {
        $eq: 1111
      }
    }
  },
])

and leads to a result that looks like:

[
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "items": [
      {
        "_id": 1111,
        "selected": true
      },
      {
        "_id": 2222,
        "selected": false
      }
    ],
    "name": "Name"
  }
]

2 Comments

HI @Vizari, Actually what you are doing wrong here is $match and $project... The $match should be used as soon as possible and the $project should be used at the end of the aggregation... And also you don't need to use $project here... You can see my updated answer...
Hi @Ashish, thanks for your reply. If i dont use the $project i have to add each field of the root document that i want to have in my result with "name": { "$first": "$name" } and $push: "$items"for my nested object?. And if i put the '$match' at the beginning of my aggregation i have only the nested object that matches that criteria in my result, but i need all of them because they have to be marked as "selected: false"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.