1

We've been struggling for hours on a query that seems easy to us and that we made through Robo 3T... The issue is now to convert it into C# and we just can't find the way and we don't even understand why it doesn't work.

We have the following query:

db.getCollection('UserCollection').update({"User.Contacts._id": ObjectId("xxx")}, 
{
    $pull: {
        "User.Contacts": {
           "_id": {$in:[ObjectId("xxx")]}
    }
  }
})

Now that our query works, we try to translate it in c# and we reached that point so far and we don't really know where the issue can come from..

public Task PullSocialInfoAsync(ObjectId contactId)
{
    var fieldName = nameof(UserContainer.User) + "." + nameof(UserContainer.User.Contacts) + "._id";
    var filter = NewFilterBuilder().Eq(fieldName, contactId);
    var update = new BsonDocument("$pull", new BsonDocument(nameof(UserContainer.User) + "." + nameof(UserContainer.User.Contacts), new BsonDocument("_id", new BsonDocument("$in", new BsonArray() { contactId }))));
    return GetCurrentCollection().FindOneAndUpdateAsync(filter, update);
}

Here you see FindOneAndUpdateAsync, but we tried we UpdateAsync as well, also we change multiple time the initialisation of our BsonArray with no success, even if the query as string match what we have on Robo 3T

Based on the above C# query, we have that output: {{ "$pull" : { "User.Contacts" : { "_id" : { "$in" : [ObjectId("xxx")] } } } }}. The most interesting part is that if I copy paste.. well it works

Any ideas?

Thanks !

1 Answer 1

2

if i understood your requirement correctly, a pullFilter is what you need.

var filter = Builders<UserCollection>.Filter.Where(u => u.User.Contacts.Any(c => c._Id == contactID));
var update = Builders<UserCollection>.Update.PullFilter(u => u.User.Contacts, c => c._Id == contactID);
collection.UpdateOne(filter, update);

here's the full program for testing if anybody's interested.

using MongoDB.Entities; // PM> Install-Package MongoDB.Entities
using MongoDB.Bson;    
using System.Linq;

namespace StackOverflow
{
    public class Program
    {
        public class UserCollection : Entity
        {
            public User User { get; set; }
        }

        public class User
        {
            public Contact[] Contacts { get; set; }
        }

        public class Contact
        {
            public ObjectId _Id { get; set; }
        }

        private static void Main(string[] args)
        {
            new DB("test");

            var contactID = ObjectId.GenerateNewId();

            (new UserCollection
            {
                User = new User
                {
                    Contacts = new[]
                    {
                        new Contact { _Id = ObjectId.GenerateNewId()},
                        new Contact { _Id = contactID}
                    }
                }
            }).Save();

            DB.Update<UserCollection>()
              .Match(u => u.User.Contacts.Any(c => c._Id == contactID))
              .Modify(b => b.PullFilter(u => u.User.Contacts, c => c._Id == contactID))
              .Execute();
        }
    }
}

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

2 Comments

Hey, thanks for your answer. I couldn't check yet but your approach seems to look like EntityFramework which is totally different from mine soo I will look into it :)
if you have c# classes that mirror the mongodb documents, then you can use lambda expressions to refer to the fields/properties for strong-typing and not use bsondocuments or magic strings like i've shown. you can ignore the code inside the snippet if you want a pure official driver solution. cheers!

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.