kheya
kheya

Reputation: 7621

How to push a List<> to a subdocument in mongodb?

I am trying to push a List to the subdocument of a document. If I insert just a single object as BsonDocument it works as shown below:

BsonDocument subdoc = new BsonDocument {
                 { "_id", ObjectId.GenerateNewId()},
                 {"name", "Mr Bob"}
                };

                var query = Query.EQ("_id", new ObjectId("1234.."));
                var upd = Update.Push("members", subdoc); <-works
                groups.Update(query, upd);

But I need to push a List. I am getting this exception:

"WriteStartArray cannot be called when State is: Initial"

This is the code that is failing:

List<BsonDocument> newMembers = new List<BsonDocument>();
BsonDocument subdoc  = new BsonDocument {
                     { "_id", ObjectId.GenerateNewId()},
                     {"name", "Mr Bob"}
                    };
newMembers.Add(subdoc );
subdoc = new BsonDocument {
                     { "_id", ObjectId.GenerateNewId()},
                     {"name", "Mr Tom"}
                    };                
newMembers.Add(subdoc);

var query = Query.EQ("_id", new ObjectId(id));
var upd = Update.Push("members", newMembers.ToBsonDocument()); <- EXCEPTION
groups.Update(query, upd);

After the insertion, I would see:

groups:
{
  _id:1,
  members:[
   {   
      _id:1,
      name: "Mr Bob"
   },
   {   
      _id:1,
      name: "Mr Tom"
   }
  ]
}

Upvotes: 2

Views: 3221

Answers (1)

Andrew Orsich
Andrew Orsich

Reputation: 53685

Since newMembers already List of BsonDocument you no need convert it to BsonDocument again.

If you want push more than one document to the a nested array you need to use $pushAll:

var upd = Update.PushAll("members", newMembers.ToArray());

In case if you will need push List items of some class you need convert each item to BsonDocument:

Lets say that newMembers is List of Member class, then if you need push List to a nested array you should do something like this:

var upd = Update.PushAll("members", newMembers.Select(x=> x.ToBsonDocument()).ToArray());

Update:

  1. To make subdocument not unique for same user names you can create algoritm that will generate same id from same user names. Most simple algoritm can just replace all spaces with underscore and make ToLower().
  2. Another way load embedd array with $slice and check uniqueness of each subdocument.

Upvotes: 1

Related Questions