Как удалить глубоко вложенный объект, который соответствует условию с MongoDB (ASP.NET Core 2.2)? - PullRequest
0 голосов
/ 01 марта 2019

Я пытаюсь удалить глубоко вложенный объект в массиве MongoDB только с идентификатором этого объекта.Для некоторого контекста здесь - мой вопрос о том, как добавить эти объекты в массив.(Этот вопрос основан на точно такой же структуре БД)

На всякий случай, вот снова структура:

{
"_id" : ObjectId("5c57169f0863d665c7f13d27"),
"CreatedUtc" : {
    "$date" : 1549211298017
},
"UpdatedUtc" : {
    "$date" : 1549211298017
},
"Description" : null,
"Address" : null,
"StorageRooms" : [
    {
        "_id" : ObjectId("5c57169f0863d665c7f13d28"),
        "CreatedUtc" : {
            "$date" : 1549211297719
        },
        "UpdatedUtc" : {
            "$date" : 1549211297719
        },
        "Description" : null,
        "StorageSections" : [
            {
                "_id" : ObjectId("5c57169f0863d665c7f13d29"),
                "CreatedUtc" : {
                    "$date" : 1549211297719
                },
                "UpdatedUtc" : {
                    "$date" : 1549211297719
                },
                "Description" : null,
                "StorageShelves" : [
                    {
                        "_id" : ObjectId("5c57169f0863d665c7f13d2a"),
                        "CreatedUtc" : {
                            "$date" : 1549211297719
                        },
                        "UpdatedUtc" : {
                            "$date" : 1549211297719
                        },
                        "Description" : null,
                        "StorageSlotIds" : [
                            ObjectId("5c57169f0863d665c7f13d26")
                        ]
                    }
                ]
            }
        ]
    }
]
}

Моя цель состоит в том, чтобы иметь метод для каждого уровня массива, чтобы удалить из него элемент только с идентификатором объекта на этом уровне вложенности .Например, для первого уровня это будет просто:

public Task<UpdateResult> RemoveStorageRoomsAsync(ObjectId id, IEnumerable<ObjectId> storageRoomIds,
        CancellationToken cancellationToken)
    {
        return UpdateAsync(id,
            Builders<StorageLocation>.Update.PullFilter(location => location.StorageRooms,
                Builders<StorageRoom>.Filter.Where(room => storageRoomIds.Contains(room.Id))),
            cancellationToken);but
    }

Но со вторым уровнем это становится сложнее.Это то, что я пытаюсь, но это не похоже на хорошее решение.Особенно на еще более низких уровнях вложенности.

public async Task<UpdateResult> RemoveStorageSectionsAsync(ObjectId id,
        IEnumerable<ObjectId> storageSectionIds,
        CancellationToken cancellationToken)
    {
        long matchedCount = 0;
        long modifiedCount = 0;
        BsonValue upsertedId = 0;

        foreach (var sectionId in storageSectionIds)
        {
            var filter = Builders<StorageLocation>.Filter.And(
                Builders<StorageLocation>.Filter.Where(
                    location => location.Id == id),
                Builders<StorageLocation>.Filter.ElemMatch(location => location.StorageRooms,
                    room => room.StorageSections.Any(section => section.Id == sectionId)));

            var update = Builders<StorageLocation>.Update.PullFilter("StorageRooms.$.StorageSections",
                Builders<StorageSection>.Filter.Where(section => section.Id == sectionId));
            var updateResultTemp = await UpdateAsync(filter, update, cancellationToken);
            matchedCount += updateResultTemp.MatchedCount;
            modifiedCount += updateResultTemp.ModifiedCount;
            upsertedId = updateResultTemp.UpsertedId; //idk
        }

        return new UpdateResult.Acknowledged(matchedCount, modifiedCount, upsertedId);
    }

Подпись метода для двух других будет:

Task<UpdateResult> RemoveStorageShelvesAsync(ObjectId id,
        IEnumerable<ObjectId> storageShelfIds,
        CancellationToken cancellationToken);

Task<UpdateResult> RemoveStorageSlotIdsAsync(ObjectId id,
        IEnumerable<ObjectId> storageSlotIds,
        CancellationToken cancellationToken);

Я знаю, что было бы легче передать идентификатор каждого объектана более высоком уровне в массиве, но это не должно быть необходимо, поскольку ObjectId (почти) всегда уникален.Кроме того, это значительно упрощает запрос XHR.

Есть ли "хороший" способ сделать это?

...