Mongodb C # - агрегация $ push, только если вложенный элемент вложенного массива соответствует условию - PullRequest
0 голосов
/ 21 октября 2019

Я уже много смотрел в интернете, прежде чем спрашивать, но не смог найти решение ...

Вот пример моих классов и объектов:

Классы:

public class A {
    [BsonId]
    public int _id {get; set;}
    public List<B> ListOfB {get; set;}
    public TypeA Type {get; set;}
}

public class B {
    public int _id {get; set;}
    public int PersonId {get; set;}
    public Person Person {get; set;} // This one is not save on the DB, it is retrieved through a Lookup
    public int Type {get; set;}
}

public class Person {
    [BsonId]
    public int _id {get; set;}
    public string Name {get; set;}
}

Объекты:

{
    "_id": 0;
    "Type", 0,
    "ListOfB": [
        {
            "_id": 0,
            "PersonId": 300,
            "Type": 0
        },
        {
            "_id": 1,
            "PersonId": 24,
            "Type": 0
        },
        {
            "_id": 2,
            "PersonId": 59,
            "Type": 1
        }
    ]
},
{
    "_id": 1;
    "Type", 1,
    "ListOfB": [
        {
            "_id": 0,
            "PersonId": 45,
            "Type": 1
        },
        {
            "_id": 1,
            "PersonId": 102,
            "Type": 0
        },
        {
            "_id": 2,
            "PersonId": 33,
            "Type": 1
        }
    ]
}
,
{
    "_id": 2;
    "Type", 1,
    "ListOfB": [
        {
            "_id": 0,
            "PersonId": 66,
            "Type": 1
        },
        {
            "_id": 1,
            "PersonId": 89,
            "Type": 0
        },
        {
            "_id": 2,
            "PersonId": 404,
            "Type": 0
        }
    ]
}

B является частью коллекции A, коллекции B. пока нетсделали что-то вроде этого, чтобы получить объекты:

BsonDocument groupMappingA = new BsonDocument();
groupMappingA.Add(new BsonElement("_id", "$_id"));

BsonDocument groupMappingB = new BsonDocument();
groupMappingB.Add(new BsonElement("_id", "$ListOfB._id"));
groupMappingB.Add(new BsonElement("PersonId", "$ListOfB.PersonId"));
groupMappingB.Add(new BsonElement("Person", "$ListOfB.Person"));
groupMappingB.Add(new BsonElement("Type", "$ListOfB.Type"));

groupMappingA.Add(new BsonElement("ListOfB", new BsonDocument(
                                                "$push", new BsonDocument(
                                                        "$cond", new BsonArray {
                                                            new BsonDocument("$eq", new BsonDocument("$ListOfB.Type", "0")),
                                                            new BsonDocument("$ListOfB", groupMappingB)
                                                        }
                                                )
                                            )
                                )
                );

AggregateUnwindOptions<A> unwindOptions = new AggregateUnwindOptions<A>() { PreserveNullAndEmptyArrays = true };
db.GetCollection<A>("A").Aggregate()
                        .match(x => x.Type == 1)
                        .Unwind("ListOfB", unwindOptions)
                        .Lookup("Person", "ListOfB.PersonId", "_id", "ListOfB.Person") // Here we set up Person through the ID saved in the object B
                        .Unwind("ListOfB.Person", unwindOptions)
                        .Group(groupMappingA)
                        .As<A>()
                        .ToList();

Итак, я пытаюсь добиться, чтобы получить все объекты A и отфильтровать все их объекты B, чтобы получить только объекты с типом, равным0, и для каждого из объектов B у меня должен быть Person, такой как:

{
    "_id": 1;
    "Type", 1,
    "ListOfB": [
        {
            "_id": 1,
            "PersonId": 102,
            "Type": 0,
            "Person": { "_id": 102, "Name": "Billy" } 
        }
    ]
},
{
    "_id": 2;
    "Type", 1,
    "ListOfB": [
        {
            "_id": 1,
            "PersonId": 89,
            "Type": 0,
            "Person": { "_id": 89, "Name": "Finn" }
        },
        {
            "_id": 2,
            "PersonId": 404,
            "Type": 0,
            "Person": { "_id": 404, "Name": "Jake" }
        }
    ]
}

Но это не работает ... Я могу получить каждый объект A типа 1 со всемиПерсональные объекты в их объектах B, но я получаю полный список B, не только те, которые относятся к типу 0.

Сначала я попытался сделать это на Mongodb Compass, но до сих пор мне не удалось, затемЯ посмотрел в Интернете, но я не смог найти то, что я ищу ... Я начал задаваться вопросом, возможно ли это вообщечтобы получить объект с фильтром в его вложенном списке?

Заранее благодарим за помощь.

1 Ответ

0 голосов
/ 21 октября 2019

Я узнал, как это сделать, я выкладываю ответ здесь на тот случай, если кому-то когда-нибудь понадобится.

BsonDocument groupMapping = new BsonDocument();
groupMapping.Add(new BsonElement("_id", new BsonDocument("$first", "$_id")));
groupMapping.Add(new BsonElement("ListOfB", new BsonDocument("$push", "$ListOfB")));

AggregateUnwindOptions<A> unwindOptions = new AggregateUnwindOptions<A>() { PreserveNullAndEmptyArrays = true };
db.GetCollection<A>("A").Aggregate()
                        .match(x => x.Type == 1)
                        .Unwind("ListOfB", unwindOptions)
                        .Match(new BsonDocument("ListOfB.Type", 0)) // Just put a match right after the Unwind, you'll be able to filter the elements of the list as you want.
                        .Lookup("Person", "ListOfB.PersonId", "_id", "ListOfB.Person")
                        .Unwind("ListOfB.Person", unwindOptions)
                        .Group(groupMapping)
                        .As<A>()
                        .ToList();
...