我有一个结构类似嵌套子文档
的文档var cookie
我想在具有圆形图的本文档中检索fooArray中的所有匹配元素。
这是我尝试过的
String?
这就是我得到的
{
"_id":ObjectId("50419077c2e6a1e18a489a0f"),
"user":"Jone Doe",
"fooArray":[
{
"plot":"circle",
"color":"yellow",
},
{
"plot":"circle",
"color":"red",
},
{
"plot":"square",
"color":"green",
}
]
}
但是它只给我第一个匹配的元素,而不是所有具有等于圆的图的元素
var filter = FilterBuilder.filter.Eq(doc => doc.User, User);
var projection = ProjectionBuilder
.Exclude(doc => doc.Id)
.Exclude(doc => doc.User)
.Include(doc => doc.FooArray)
.ElemMatch(x => x.FooArray, y => y.Plot == "circle");
var definition = new OperationDefinitions<ShapeDocument> { Filter = filter };
return await Performer.Perform(definition, async (def, collection) =>
{
var findResult = collection.Find(def.Filter).Project(projection);
var result = await findResult.SingleOrDefaultAsync();
});
我确实阅读了提及的mongodb文档
“ $ elemMatch运算符将查询结果中字段的内容限制为仅包含与$ elemMatch条件匹配的第一个元素。”
不太确定如何实现!
答案 0 :(得分:1)
该问题并未完全描述用例,因此我根据一些假设为您提供了一些潜在的选项供您探索,尤其是它们取决于LINQ是否可用以及将单个文档作为目标。一段时间(而且您可能不想要超出实际需要的代码):
1)您所拥有的产品有所不同。使用带有投影和LINQ表达式的标准find
。
var projection = Builders<ShapeDocument>.Projection
.Expression(x => x.fooArray.Where(y => y.plot == "circle"));
var items1 = collection
.Find(x => x.user == "Jone Doe")
.Project(projection)
.ToList();
2)使用聚合管道(您可以使用与上面相同的投影)
var pipeline = collection
.Aggregate()
.Match(x => x.user == "Jone Doe")
.Project(i => new
{
x = i.fooArray.Where(x => x.plot == "circle")
});
var items2 = pipeline.SingleOrDefault();
3)将文档连同所有数组元素一起拉回,然后使用LINQ在本地进行过滤。从好的方面来说,这是少量的可读代码,但是,确实会在过滤之前将整个文档带回来。根据您的确切使用情况,这可能是可以接受的。
var items3 = collection.AsQueryable()
.SingleOrDefault(x => x.user == "Jone Doe")
.fooArray.Where(x => x.plot == "circle");
如果不是真的要使用LINQ,则有一个示例here,该示例显示了如何将投影转换为我们的LINQ。完全未经测试,但可能类似于:
var filter = new BsonDocument {
{"input", "$items"},
{"as", "item" },
{"cond", new BsonDocument {
// Fill in the condition values
{ "", new BsonArray { "", xxx } } }
}
};
var project = new BsonDocument {
{ "items", new BsonDocument { { "$filter", filter} } }
};
var pipeline = collection.Aggregate().Project(project);
答案 1 :(得分:0)
这是一个使用MongoDB.Entities的简单解决方案,它只是c#驱动程序的包装库。
using MongoDB.Driver.Linq;
using MongoDB.Entities;
using System.Linq;
namespace StackOverflow
{
public class User : Entity
{
public string Name { get; set; }
public Foo[] Foos { get; set; }
}
public class Foo
{
public string Plot { get; set; }
public string Color { get; set; }
}
class Program
{
static void Main(string[] args)
{
new DB("test");
var user = new User
{
Name = "Jone Doe",
Foos = new[]
{
new Foo{ Plot = "circle", Color="yellow"},
new Foo{ Plot = "circle", Color="red"},
new Foo{ Plot = "square", Color="green"},
}
};
user.Save();
var circularFoos = DB.Collection<User>()
.Where(u => u.Name == "Jone Doe")
.SelectMany(u => u.Foos)
.Where(f=>f.Plot=="circle").ToArray();
}
}
}
这是它生成的汇总查询:
{
"$match": {
"Name": "Jone Doe"
}
},
{
"$unwind": "$Foos"
},
{
"$project": {
"Foos": "$Foos",
"_id": 0
}
},
{
"$match": {
"Foos.Plot": "circle"
}
}
答案 2 :(得分:0)
我想出了一种简洁的方法
var filter = FilterBuilder.filter.Eq(doc => doc.User, User);
var definition = new OperationDefinitions<ShapeDocument> { Filter = filter };
return await Performer.Perform(definition, async (def, collection) =>
{
var findResult = collection.Find(def.Filter).Project(doc => doc.fooArray.Where(x => x.Plot == "Circle"));
var result = await findResult.SingleOrDefaultAsync();
}