1

been trying for some time now to run a delete query against a mongodb collection; strongly typed objects, parents, nested children, each with nested grandchildren. i want to delete a specific grandchild, which is in a specific child, in a specific parent. i can get to MatchedCount = 1, but ModifiedCount is always 0 and the delete doesn't happen. i have tried many variations of the query, both from here and also using the AI engine on the mongo website. nothing works.

The entity structure is what you'd expect:

public class Parent
{
    public string Id {get; set;}
    public Child[] Children {get; set;}
}

public class Child
{
    public Guid Id {get; set;}
    public Grandchild[] Grandchildren {get; set;}
}

public class Grandchild
{
    public Guid Id {get; set;}
    public string Name {get; set;}
}

here is my latest attempt:

var filter = Builders<Parent>.Filter.Eq(x => x.Id, parentId);

var update = Builders<Parent>.Update.Pull(
  "Children.$[child].GrandChildren",
   Builders<GrandChild>.Filter.Eq(gc => gc.Id, Guid.Parse(grandChildId))
);

var arrayFilters = new List<ArrayFilterDefinition>
{
  new BsonDocumentArrayFilterDefinition<BsonDocument>(new BsonDocument("child._id", childId))
};

var updateOptions = new UpdateOptions { ArrayFilters = arrayFilters };

var result = await _parentCollection.UpdateOneAsync(filter, update, updateOptions);

return result.ModifiedCount == 1;

updating/deleting children is simple enough but i cannot get to the grandchild somehow. has anyone any idea what i am doing wrong?

EDIT:

in case anyone else is wrestling with similar - i now have a working solution to this, after 3 days (!!!) and some rehashing some of what i got from mongodb AI. i have used t-sql for 25 years and never suspected that something so simple could be so difficult to figure out. easy when you know how!

        var filter = Builders<Parent>.Filter.And(
            Builders<Parent>.Filter.Eq(p => p.Id, parentId),
            Builders<Parent>.Filter.ElemMatch(p => p.Children, c => c.Id == Guid.Parse(childId)));

        var update = Builders<Parent>.Update.PullFilter(
            "Children.$.GrandChildren",
            Builders<GrandChild>.Filter.Eq(gc => gc.Id, Guid.Parse(grandChildId))
        );

        var result = await _parentCollection.UpdateOneAsync(filter, update);

        return result.ModifiedCount == 1;
8
  • Try a recursive query : stackoverflow.com/questions/42787293/mongodb-recursive-query Commented Sep 4 at 12:24
  • thanks for your reply. i am not clear on how recursion would help in this case? my structure is strictly hierarchical. i need to go into the data once, to pinpoint what i am looking for and then remove it. Commented Sep 4 at 14:26
  • You have a parent, children, and grandchildren. Yes it is hierarchal, but you are having issues getting to the grandchildren which is why recursion is needed. Commented Sep 4 at 15:42
  • From Mongo themselves: "MongoDB does not support truly recursive queries for nested arrays," Commented Sep 4 at 16:16
  • Iterate over the "graph"; adding the entities (references) to a "to be deleted" collection. Now delete each entity in the "to be deleted" collection from the "target" collection ... in reverse order. Commented Sep 4 at 17:23

1 Answer 1

0

Glad you found a solution. The $elemMatch used helps find the specific grandchild here and the $pull operator helps remove it from the array of grandchildren. Another approach could've been:

//Delete a nested grandchild 
var parentId = "Parent1";
var grandchildIdToDelete = Guid.Parse("eff8318f-f464-4296-8ea7-67e670005ffb");
var filter = Builders<BsonDocument>.Filter.Eq("_id", parentId);
var update = Builders<BsonDocument>.Update.PullFilter("Children.$[].Grandchildren",
    Builders<BsonDocument>.Filter.Eq("_id", grandchildIdToDelete));
var result = _collection.UpdateOne(filter, update);
Console.WriteLine($"Modified Count: {result.ModifiedCount}");
Sign up to request clarification or add additional context in comments.

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.