MongoDb / C# отфильтруйте и получите все вложенные документы
У меня трудности с запросом коллекции Mongo-DB.
Документ, который я использую
public class Customer
{
public ObjectId Id { get; set; }
public int CustomerId { get; set; }
public List<Address> Addresses { get; set; }
}
public class Address
{
public string Name { get; set; }
}
Некоторые сэмплы-данные
{
CustomerId: 2,
Addresses: [
{
Name: "Daniel"
},
{
Name: "Eric"
},
{
Name: "Dan"
}
]
}
Теперь я хочу запросить документы по CustomerId и отфильтровать некоторые значения-адреса, чтобы вернуть все адреса с таким именем, как%Dan%. Поскольку сбор адресов может быть огромным, я хочу уже фильтровать эти адреса во время запроса
var mdb = mongoClient.GetDatabase("test");
var collection = mdb.GetCollection<WebApi>("Customer");
var builder = Builders<Customer>.Filter;
var searchTerm = "Dan";
При таком запросе он работает, но содержит все адреса:
var filter = builder.And(builder.Eq("InstallationId", 2),
builder.Regex("Addresses.Name", new BsonRegularExpression(".*" + searchTerm + ".*", "i")))
var result = collection.Find(filter).FirstOrDefault();
Что я хотел бы получить:
[
{
Name: "Daniel"
},
{
Name: "Dan"
}
]
или же
{
CustomerId: 2,
Addresses: [
{
Name: "Daniel"
},
{
Name: "Dan"
}
]
}
Я также попробовал несколько подходов с Aggregate/Match/Project, но не смог заставить его работать. "AsQueryable" также не работает, так как IndexOf не реализован в драйвере.
collection.AsQueryable().Where(x => x.CustomId == 2).SelectMany(x =>
x.Addresses.Where(a => a.Name.IndexOf(searchTerm, StringComparison.InvariantCultureIgnoreCase) >= 0).ToList();
Используемые версии:
- MongoDB.Driver v 2.6.1 (также Bson)
- .Net Framework 4.5.2
1 ответ
Это должно заставить вас идти:
var result = collection
.Aggregate()
.Match(c => c.CustomerId == 2)
.Project(c => new
{
c.CustomerId,
Addresses = c.Addresses.Where(a => a.Name.IndexOf(searchTerm) != -1)
})
.ToList();
Драйвер переведет это на:
db.Customer.aggregate([{
$match: { CustomerId: 2 }
}, {
$project: {
CustomerId: "$CustomerId",
Addresses: {
$filter: {
input: "$Addresses",
as: "a",
cond: {
$ne: [ { $indexOfBytes: [ "$$a.Name", "Dan" ] }, -1 ]
}
}
},
_id: 0
}
}])
Для версии без учета регистра будет возможность использовать $regex на каком-то этапе в будущем (см. https://jira.mongodb.org/browse/SERVER-11947). Однако то, что вы можете сделать только сейчас, это использовать ToUpper()
:
var result = collection
.Aggregate()
.Match(c => c.CustomerId == 2)
.Project(c => new
{
c.CustomerId,
Addresses = c.Addresses.Where(a => a.Name.ToUpper().IndexOf(searchTerm.ToUpper()) != -1)
})
.ToList();