0

I know this has been asked before, but I have yet to find a solution that works efficiently. I am working with the MongoDB C# driver, though this is more of a general question about MongoDB operations.

I have a document structure that looks something like this:

field1: value1
field2: value2
...
users: [ {...user 1 subdocument...}, {...user 2 subdocument...}, ... ]

Some facts:

  • Each user subdocument includes further sub-arrays & subdocuments (so they're fairly complex).
  • The average users array only contains about 5 elements, but in the worst case can surpass 100.
  • Several thousand update operations on multiple users may be conducted per day in this system, each on one document at a time. Larger arrays will receive more frequent updates due to their data size.

I am trying to figure out how to do this efficiently. From what I've heard, you cannot directly set several array elements to new values all at once, so I had to try something else.

I tried using the $pullAll / $AddToSet + $each operations to remove the old array and replace it with a modified one. I am aware that $pullall can remove only the elements that I need as well, but I would like to preserve the order of elements.

The C# code:

try
{
    WriteConcernResult wcr = collection.Update(query,
    Update.Combine(Update.PullAll("users"),
    Update.AddToSetEach("users", newUsers.ToArray())));
}
catch (WriteConcernException wce)
{
    return wce.Message;
}

In this case newUsers is aList<BsonValue>converted to an array. However I am getting the following exception message:

Cannot update 'users' and 'users' at the same time

By the looks of it, I can't have two update statements in use on the same field in the same write operation.

I also tried Update.Set("users", newUsers.ToArray()), but apparently the Set statement doesn't work with arrays, just basic values:

Argument 2: cannot convert from 'MongoDB.Bson.BsonValue[]' to 'MongoDB.Bson.BsonValue'

So then I tried converting that array to a BsonDocument:

Update.Set("users", newUsers.ToArray().ToBsonDocument());

And got this:

An Array value cannot be written to the root level of a BSON document.

I could try replacing the whole document, but that seems like overkill and definitely not very efficient.

So the only thing I can think of now is to run two separate write operations: one to remove the unwanted old users and another to replace them with their newer versions:

WriteConcernResult wcr = collection.Update(query, Update.PullAll("users"));
WriteConcernResult wcr = collection.Update(query, Update.AddToSetEach("users", newUsers.ToArray()));

Is this my best option? Or is there another, better way of doing this?

2 Answers 2

2

Your code should work with a minor change:

Update.Set("users", new BsonArray(newUsers));

BsonArray is a BsonValue, where as an array of documents is not and we don't implicitly convert arrays like we do other primitive values.

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

Comments

0

this extension method solve my problem:

public static class MongoExtension
{
    public static BsonArray ToBsonArray(this IEnumerable list)
    {
        var array = new BsonArray();
        foreach (var item in list)
            array.Add((BsonValue) item);

        return array;
    }
}

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.