2

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 :)

0

2 Answers 2

1

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();
Sign up to request clarification or add additional context in comments.

Comments

0

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.

Comments

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.