2

I have the following document in a collection called Users in MongoDB. I am trying to insert a <SpecificBeer> into beersInCellar[] of the mycellar cellar. I've tried all kinds of combinations in the filter and update objects but just can't wrap my head around inserting into a nested array. I know how to find a document and insert things into it, just not into an array in that document.

{
    "_id" : ObjectId("5920751b6d4f6a27cf7985a8"),
    "name" : "FullName",
    "emailAddress" : "[email protected]",
    "cellars" : [
        {
            "cellarId" : "mycellar",
            "cellarName" : "My Cellar",
            "beersInCellar" : [ ]
        }
    ]
}

SpecificBeer model:

public class SpecificBeer
        {
            public string ourid 
            { 
                get
                {
                    return ID.ToString();
                } 
                set
                { 
                    ID = ObjectId.Parse(value); 
                }
            }
            [BsonId]
            private ObjectId ID {get; set;}
            public string year { get; set; }
            public string variant { get; set; }
            public string quantity { get; set; }
            public string numberForTrade { get; set; }
        }

Insert method

public async Task<SpecificBeer> AddBeerToList(string id, SpecificBeer specificBeer, string cellarId)
{
        var filter = Builders<User>.Filter.Eq(e => e.userId, id) & Builders<User>.Filter.Eq(e => e.cellars, cellarId);

        var update = Builders<Cellar>.Update.Push<SpecificBeer>(e => e.beersInCellar, specificBeer);

        await _collection.FindOneAndUpdateAsync(filter, update);
        return specificBeer;
}

1 Answer 1

4

You have to use $positional operator.

You've to include the field(cellarId) from the cellars for mongoDB to locate the index of element and replace the placeholder($) with the found index from query part in the update part to push the element in beersInCellar.

Something like

 var filter = Builders<User>.Filter.Eq(e => e.name, "FullName") & Builders<User>.Filter.ElemMatch(e => e.cellars, Builders<Cellar>.Filter.Eq(e => e.cellarId, "mycellar"));
 var update = Builders<User>.Update.Push(e => e.cellars[-1].beersInCellar, specificBeer);

Shell Query for reference:

db.collection.update({"name" : "FullName", "cellars":{$elemMatch:{"cellarId":"mycellar"}}},{$push:{"cellars.$.beersInCellar":{"quantity":1, "year":1986}}})

MongoDB doesn't have first class support for updating fields ( for example quantity ) in the nesting arrays inside arrays.

You can track the jira which is going to allow multiple level updates.

https://jira.mongodb.org/browse/SERVER-27089

You may want to revisit your structure for now. Try promoting the beersInCellar arrays to top level.

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

1 Comment

Wow that was a ton of info, thank you so much! I'll probably rethink my schema.

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.