简体   繁体   中英

Query a deeply nested object in arrays using MongoDB and C#

I'm pretty new to MongoDB and already I face a sweaty challenge. I'm trying to get an element from an array with objects inside of an array with objects (if that makes sense). This is how a document looks like and what I am trying to get:

https://i.imgur.com/W4Wfmhc.png

So basically the structure is as follows:

  • OptionMenus
    • OptionMenuSubject
      • OptionMenuItem

To get the OptionMenuItem I matched to pull it off using the aggregation pipeline tool from MongoDB Compass tool

[{
    $unwind: {
        path: '$subjects'
    }
}, {
    $unwind: {
        path: '$subjects.items'
    }
}, {
    $project: {
        _id: '$subjects.items._id',
        item: '$subjects.items'
    }
}, {
    $match: {
        _id: ObjectId('5e6eaef8ae35a418f4f6dbd4')
    }
}]

Then I tried translating this to C# with no success, this is as far as I've come:

        var optionMenuItem = await collection.Aggregate()
           .Unwind<OptionMenu, OptionMenuSubject>(i => i.Subjects)
           .Unwind<OptionMenuSubject, OptionMenuItem>(i => i.Items)
           .Match(i => i.Id == id)
           .ToListAsync();

If somebody knows what I'm doing wrong or how I can pull this off it would be very much appreciated :)

unwinding unfiltered data is not a good idea because it creates a lot of data in mongodb memory and you might reach the 100mb aggregation pipeline limit. so try to always filter and narrow down records before unwinding. i believe the following pipeline would give the result you need:

db.collection.aggregate([
    {
        $match: {
            'subjects.items._id': ObjectId('5e6eaef8ae35a418f4f6dbd4')
        }
    },
    {
        $unwind: '$subjects'
    },
    {
        $unwind: '$subjects.items'
    },
    {
        $match: {
            'subjects.items._id': ObjectId('5e6eaef8ae35a418f4f6dbd4')
        }
    },
    {
        $replaceWith: '$subjects.items'
    }
])

here's a convenient way to execute this pipeline with c#. you can read more about how it works here .

This is how I eventually solved it. Not my proudest work because it doesn't have the strong typing in it, but it works:

var collection = Database.GetCollection<BsonDocument>(_collectionName);    
var query = await collection.Aggregate()
                .Match(i => i["subjects.items._id"] == ObjectId.Parse(id))
                .Unwind(i => i["subjects"])
                .Unwind(i => i["subjects.items"])
                .Match(i => i["subjects.items._id"] == ObjectId.Parse(id))
                .ReplaceRoot(i => i["subjects.items"])
                .FirstOrDefaultAsync();

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