我有以下文档架构。
{
"name":"Name",
"region":"New Jersey",
"address":"92 Something Rd",
"city":"Jersey City",
"state":"NJ",
"zipCode":"07302",
"country":"USA",
amenities":[
"Sauna",
"Locker",
"Shop"
],
"services":[
"Car Rental",
"Transportation"
]
}
我希望一次调用服务器来获取所有匹配任何过滤器参数的文档,其中map 1-1表示"state" = "NJ" OR "city" = "Jersey City"
,但是当列表的任何值包含在任何文档数组子中时,示例{ {1}}。它应该是所有可能过滤器的OR连接。
使用C#MongoDB驱动程序到目前为止我在[ "Sauna", "Locker" ] ANY IN "amenities"
课程中提出了以下方法,但没有返回所需的结果。
MongoRepository
我希望它是通用的,所以客户端可以调用这样的方法。
public async Task<IEnumerable<T>> DocumentsMatchEqFieldValueAsync<T>(string collectionName,
IDictionary<string, string> fieldsValues = null,
IDictionary<string, IEnumerable<string>> fieldsWithEnumerableValues = null,
IEnumerable<ObjectId> ids = null)
{
var cursor = await GetEqAsyncCursor<T>(collectionName, fieldsValues, fieldsWithEnumerableValues, ids).ConfigureAwait(false);
return await cursor.ToListAsync().ConfigureAwait(false);
}
protected Task<IAsyncCursor<T>> GetEqAsyncCursor<T>(string collectionName,
IDictionary<string, string> fieldsValues = null,
IDictionary<string, IEnumerable<string>> fieldsWithEnumerableValues = null,
IEnumerable<ObjectId> ids = null)
{
var collection = GetCollection<T>(collectionName);
var builder = Builders<T>.Filter;
// Not sure if this is the correct way to initialize it because it seems adding an empty filter condition returning ALL document;
FilterDefinition<T> filter = new BsonDocument();
if (fieldsValues != null &&
fieldsValues.Any())
{
filter = filter | fieldsValues
.Select(p => builder.Eq(p.Key, p.Value))
.Aggregate((p1, p2) => p1 | p2);
}
if (fieldsWithEnumerableValues != null &&
fieldsWithEnumerableValues.Any())
{
filter = filter | fieldsWithEnumerableValues
.Select(p => builder.AnyEq(p.Key, p.Value))
.Aggregate((p1, p2) => p1 | p2);
}
if (ids != null &&
ids.Any())
{
filter = filter | ids
.Select(p => builder.Eq("_id", p))
.Aggregate((p1, p2) => p1 | p2);
}
return collection.FindAsync(filter);
}
我希望文档有public async Task should_return_any_records_matching_all_possible_criteria()
{
// Arrange
IDocumentRepository documentRepository = new MongoRepository(_mongoConnectionString, _mongoDatabase);
// Act
var documents = await documentRepository.DocumentsMatchEqFieldValueAsync<BsonDocument>(Courses,
fieldsValues: new Dictionary<string, string>
{
{ "state", "NJ" },
{ "city", "Jersey City" }
},
fieldsWithEnumerableValues: new Dictionary<string, IEnumerable<string>>
{
{ "services", new List<string> { "Car Rental", "Locker" } },
{ "amenities", new List<string> { "Sauna", "Shop" } }
});
// Assert
documents.ShouldNotBeEmpty();
}
。
答案 0 :(得分:3)
我发布了一些研究方法后面我最终使用的方法,以便将来帮助任何想要做同样事情的人。我找到了如何使用正则表达式here进行查询,编写简单的MongoDB查询并将它们添加到过滤器集合here以及如何调试生成的查询here。
使用Studio 3T客户端获取所有这些信息和一些实验后,找到方法。
protected Task<IAsyncCursor<T>> GetEqAsyncCursor<T>(string collectionName,
IDictionary<string, string> fieldEqValue = null,
IDictionary<string, string> fieldContainsValue = null,
IDictionary<string, IEnumerable<string>> fieldEqValues = null,
IDictionary<string, IEnumerable<string>> fieldElemMatchInValues = null,
IEnumerable<ObjectId> ids = null)
{
var collection = GetCollection<T>(collectionName);
var builder = Builders<T>.Filter;
IList<FilterDefinition<T>> filters = new List<FilterDefinition<T>>();
if (fieldEqValue != null &&
fieldEqValue.Any())
{
filters.Add(fieldEqValue
.Select(p => builder.Eq(p.Key, p.Value))
.Aggregate((p1, p2) => p1 | p2));
}
if (fieldContainsValue != null &&
fieldContainsValue.Any())
{
filters.Add(fieldContainsValue
.Select(p => builder.Regex(p.Key, new BsonRegularExpression($".*{p.Value}.*", "i")))
.Aggregate((p1, p2) => p1 | p2));
}
if (fieldEqValues != null &&
fieldEqValues.Any())
{
foreach (var pair in fieldEqValues)
{
foreach (var value in pair.Value)
{
filters.Add(builder.Eq(pair.Key, value));
}
}
}
if (fieldElemMatchInValues != null &&
fieldElemMatchInValues.Any())
{
var baseQuery = "{ \"%key%\": { $elemMatch: { $in: [%values%] } } }";
foreach (var item in fieldElemMatchInValues)
{
var replaceKeyQuery = baseQuery.Replace("%key%", item.Key);
var bsonQuery = replaceKeyQuery.Replace("%values%",
item.Value
.Select(p => $"\"{p}\"")
.Aggregate((value1, value2) => $"{value1},
{value2}"));
var filter = BsonSerializer.Deserialize<BsonDocument>(bsonQuery);
filters.Add(filter);
}
}
if (ids != null &&
ids.Any())
{
filters.Add(ids
.Select(p => builder.Eq("_id", p))
.Aggregate((p1, p2) => p1 | p2));
}
var filterConcat = builder.Or(filters);
// Here's how you can debug the generated query
//var documentSerializer = BsonSerializer.SerializerRegistry.GetSerializer<T>();
//var renderedFilter = filterConcat.Render(documentSerializer, BsonSerializer.SerializerRegistry).ToString();
return collection.FindAsync(filterConcat);
}