简体   繁体   中英

Query nested arrays of subdocuments

EDIT: The query should not user the '&" characters. Those or for updates.

ANSWER: Courtesy of Gibbs

correct: 
const result : any = await mongoose.model('Events').update(
    {
        _id: eventId,
        "groups._id": groupId,
        "groups.users._id": userId
    },

incorrect:
const result: any = await mongoose.model('Events').findOne(
    {
        _id: eventId,
        "groups._id": "5f270416e7964b20d6f8953e",
        "groups.$.users": { _id: '5f270877b4942d2528885dbd' }
    })
    // OR:
    {
        _id: eventId,
        "groups._id": "5f270416e7964b20d6f8953e",
        "groups.$.users._id" : '5f270877b4942d2528885dbd',  
    })

With only the first two predicates,( eventId and groups [$_id] ) it returns the event. But the third breaks.

Does anybody know why this returns null (object ids are copied directly from the db) Thanks!

{
    "_id": ObjectId("5f270416e7964b20d6f8953d"),
    "lastRounds": [],
    "name": "EpicFest",
    "start": 1596392488896.0,
    "end": 1596392500896.0,
    "groups": [
      {
        "_id": ObjectId("5f270416e7964b20d6f8953e"),
        "name": "Vossius",
        "users": [
          {
            "created": 1596393590778.0,
            "sessionId": null,
            "feedBack": {
              "messagesSent": 0,
              "messagesSentLiked": 0,
              "messagesReceived": 0,
              "messagesReceivedLiked": 0,
              "userFeedbackReceived": [],
              "chatFeedbackReceived": [],
              "_id": ObjectId("5f270877b4942d2528885dbe")
            },
            "_id": ObjectId("5f270877b4942d2528885dbd"),
            "image": "someAvatr",
            "name": "hans",
            "groupId": "5f270416e7964b20d6f8953e",
            "results": []
          },
          
        ]
      },
      {
        "_id": ObjectId("5f270416e7964b20d6f8953f"),
        "users": [],
        "name": "Ignatius"
      }
    ],
    "results": [],
    "theses": [],
    "rounds": 10,
    "schedule": [],
    "__v": 4
}

Use the aggregate pipeline to fetch based on the inner sub-document.

In the first match stage, filter by eventId and do a $elemMatch on the inner groupId . Next, unwind the group and groups.user .

Post unwinding you will have a flat object structure that you can again apply filter upon and, just apply a match stage on groups.user._id now.

const pipeline = [
    {
        $match: {
            _id: eventId,
            groups: {
                $elemMatch: mongoose.Types.ObjectId('5f270416e7964b20d6f8953e')
            }
        }
    },
    {
        $unwind: '$groups'
    },
    {
        $unwind: '$groups.users'
    },
    {
        $match: {
            '$groups.users._id': mongoose.Types.ObjectId('5f270877b4942d2528885dbd')
        }
    }
];
const result: any = await mongoose.model('Events').aggregate(pipeline).exec();

Mongo Play

db.collection.find({
  _id: ObjectId("5f270416e7964b20d6f8953d"),
  "groups._id": ObjectId("5f270416e7964b20d6f8953e"),
  "groups.users._id": ObjectId("5f270877b4942d2528885dbd")
})

You tried to use String "5f270416e7964b20d6f8953e" . It should be ObjectId

You can use . notation to access a nested element or $elemMatch

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM