Есть 2 способа сделать это, либо путем агрегации, либо с помощью поиска с выражением .
Мы рассмотрим агрегацию, так как для меня она протекает немного проще .
Итак, начнем с того, что у нас будет 2 модели для MongoDB, как вы сказали.
public class DocumentOne
{
public string Id { get; set; }
public string InnerId { get; set; }
public DocumentTwo[] InnerDocuments { get; set; }
}
public class DocumentTwo
{
public string Id { get; set; }
public string AnotherField { get; set; }
}
Затем нам понадобится вторая проекция, чтобы отслеживать события позже, когда мы развернуть внутренние документы:
public class DocumentOneProjection
{
public string Id { get; set; }
public string InnerId { get; set; }
public DocumentTwo InnerDocuments { get; set; }
}
Итак, мы добавим некоторые данные в MongoDB, чтобы поиграть с
var client = new MongoClient();
var database = client.GetDatabase("test");
var collection = database.GetCollection<DocumentOne>("documents");
await database.DropCollectionAsync(collection.CollectionNamespace.CollectionName);
await collection.InsertManyAsync(new[]
{
new DocumentOne()
{
Id = "1", InnerId = "10", InnerDocuments = new[]
{
new DocumentTwo()
{
Id = "11"
}
}
},
new DocumentOne()
{
Id = "2", InnerId = "20", InnerDocuments = new[]
{
new DocumentTwo()
{
Id = "20"
}
}
},
new DocumentOne()
{
Id = "3", InnerId = "30", InnerDocuments = new[]
{
new DocumentTwo()
{
Id = "30"
},
new DocumentTwo()
{
Id = "31"
}
}
}
});
Затем мы сможем создать запрос агрегирования
var items = await collection.Aggregate()
.Unwind(x => x.InnerDocuments)
.AppendStage<BsonDocument>(
@"{ $addFields: { matchInner: { $cmp: [ ""$InnerId"", ""$InnerDocuments._id"" ] } } }")
.Match("{ matchInner: { $ne : 0 } }") // 0 if the two values are equivalent.
.AppendStage<DocumentOneProjection>(
@"{ $unset: ""matchInner"" }")
.ToListAsync();
Этот запрос начинается с разворачивания всех внутренних документов, это создаст документ для каждого документа в массиве (https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/)
Затем он создает новое поле, для которого мы затем создадим соответствие позже, здесь используется сравнение ($ cmp - https://docs.mongodb.com/manual/reference/operator/aggregation/cmp/)
Затем мы просто сопоставляем новое поле и затем выполняем запрос, чтобы получить обратно документы.