Поскольку ваш документ многоуровневый, вы должны использовать оператор $ filter . В C# легко использовать LINQ для такого запроса, поскольку он автоматически генерирует $filter
за кулисами, и вы сохраняете строго типизированный запрос:
var q = from channel in mongoDBCollection.AsQueryable()
from episode in channel.Episodes
select new Episode()
{
Id = episode.Id,
Name = episode.Name,
Tracks = episode.Tracks.Where(x => x.Id == trackId)
};
var query = q.Where(x => x.Tracks.Any());
var result = query.ToList();
Трубопровод агрегации, который генерируется MongoDB. NET драйвер выглядит следующим образом:
{
"aggregate" : "col",
"pipeline" : [
{ "$unwind" : "$Episodes" },
{
"$project" : {
"Id" : "$Episodes._id",
"Name" : "$Episodes.Name",
"Tracks" : {
"$filter" : {
"input" : "$Episodes.Tracks",
"as" : "x",
"cond" : { "$eq" : ["$$x._id", "5e460dbe2bc5e70c9cfeac21"] }
}
},
"_id" : 0
}
},
{
"$match" : {
"Tracks" : {
"$ne" : null,
"$not" : { "$size" : 0 }
}
}
}],
"cursor" : { },
}
РЕДАКТИРОВАТЬ:
Чтобы повысить производительность вышеупомянутого запроса, вы можете рассмотреть возможность фильтрации на уровне channel
, добавив оператор where
:
from channel in mongoDBCollection.AsQueryable()
where channel.Id == channelId
РЕДАКТИРОВАТЬ: становится немного сложнее, когда вы хотите вернуть Channel
. Я бы предложил вернуть аномичный тип, который содержит и Channel
, и Episode
, и объединить их в памяти, поскольку это позволит вам выполнить большую часть фильтрации на стороне базы данных и получить наилучшую производительность:
var q = from channel in mongoDBCollection.AsQueryable()
where channel.Id == "5e4606e6ae7b090688671416"
from episode in channel.Episodes
select new
{
Channel = new Channel(){ Id = channel.Id, Name = channel.Name},
Episode = new Episode()
{
Id = episode.Id,
Name = episode.Name,
Tracks = episode.Tracks.Where(x => x.Id == trackId)
}
};
var query = q.Where(x => x.Episode.Tracks.Any());
var result = query.ToList();