我有以下的MongoDB的查询工作:
db.Entity.aggregate(
[
{
"$match":{"Id": "12345"}
},
{
"$lookup": {
"from": "OtherCollection",
"localField": "otherCollectionId",
"foreignField": "Id",
"as": "ent"
}
},
{
"$project": {
"Name": 1,
"Date": 1,
"OtherObject": { "$arrayElemAt": [ "$ent", 0 ] }
}
},
{
"$sort": {
"OtherObject.Profile.Name": 1
}
}
]
)
这检索与来自另一个集合匹配对象加入对象的列表。
有谁知道我怎么能在C#中使用LINQ两种或通过使用这个确切的字符串中使用呢?
我试着用下面的代码,但它似乎无法找到该类型QueryDocument
和MongoCursor
-我认为他们已经被弃用?
BsonDocument document = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>("{ name : value }");
QueryDocument queryDoc = new QueryDocument(document);
MongoCursor toReturn = _connectionCollection.Find(queryDoc);
没有必要解析JSON。 这里的一切其实是可以用任何LINQ或总结流利的界面直接完成。
只需使用一些示范课,因为这个问题并没有真正提供多少去。
建立
基本上我们有两个集合在这里,是
实体
{ "_id" : ObjectId("5b08ceb40a8a7614c70a5710"), "name" : "A" }
{ "_id" : ObjectId("5b08ceb40a8a7614c70a5711"), "name" : "B" }
和其他人
{
"_id" : ObjectId("5b08cef10a8a7614c70a5712"),
"entity" : ObjectId("5b08ceb40a8a7614c70a5710"),
"name" : "Sub-A"
}
{
"_id" : ObjectId("5b08cefd0a8a7614c70a5713"),
"entity" : ObjectId("5b08ceb40a8a7614c70a5711"),
"name" : "Sub-B"
}
和一对夫妇的类将它们绑定到,只是非常基本的例子:
public class Entity
{
public ObjectId id;
public string name { get; set; }
}
public class Other
{
public ObjectId id;
public ObjectId entity { get; set; }
public string name { get; set; }
}
public class EntityWithOthers
{
public ObjectId id;
public string name { get; set; }
public IEnumerable<Other> others;
}
public class EntityWithOther
{
public ObjectId id;
public string name { get; set; }
public Other others;
}
查询
流利的接口
var listNames = new[] { "A", "B" };
var query = entities.Aggregate()
.Match(p => listNames.Contains(p.name))
.Lookup(
foreignCollection: others,
localField: e => e.id,
foreignField: f => f.entity,
@as: (EntityWithOthers eo) => eo.others
)
.Project(p => new { p.id, p.name, other = p.others.First() } )
.Sort(new BsonDocument("other.name",-1))
.ToList();
请求发送到服务器:
[
{ "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
{ "$lookup" : {
"from" : "others",
"localField" : "_id",
"foreignField" : "entity",
"as" : "others"
} },
{ "$project" : {
"id" : "$_id",
"name" : "$name",
"other" : { "$arrayElemAt" : [ "$others", 0 ] },
"_id" : 0
} },
{ "$sort" : { "other.name" : -1 } }
]
也许最容易理解的,因为流畅的界面基本相同,一般BSON结构。 在$lookup
阶段都具有相同的参数和$arrayElemAt
为代表, First()
对于$sort
,你可以简单地提供一个BSON文件或其他有效的表达式。
另一种是较新的表现形式$lookup
与上述MongoDB的3.6和子流水线声明。
BsonArray subpipeline = new BsonArray();
subpipeline.Add(
new BsonDocument("$match",new BsonDocument(
"$expr", new BsonDocument(
"$eq", new BsonArray { "$$entity", "$entity" }
)
))
);
var lookup = new BsonDocument("$lookup",
new BsonDocument("from", "others")
.Add("let", new BsonDocument("entity", "$_id"))
.Add("pipeline", subpipeline)
.Add("as","others")
);
var query = entities.Aggregate()
.Match(p => listNames.Contains(p.name))
.AppendStage<EntityWithOthers>(lookup)
.Unwind<EntityWithOthers, EntityWithOther>(p => p.others)
.SortByDescending(p => p.others.name)
.ToList();
请求发送到服务器:
[
{ "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
{ "$lookup" : {
"from" : "others",
"let" : { "entity" : "$_id" },
"pipeline" : [
{ "$match" : { "$expr" : { "$eq" : [ "$$entity", "$entity" ] } } }
],
"as" : "others"
} },
{ "$unwind" : "$others" },
{ "$sort" : { "others.name" : -1 } }
]
流畅的“生成器”不支持语法直接还,也不LINQ表达式支持$expr
运营商,但你仍然可以使用构建BsonDocument
和BsonArray
或其他有效表达式。 在这里,我们也“式的” $unwind
结果以应用$sort
使用表达式,而不是BsonDocument
前面所示为。
除了其他用途,“子流水线”的首要任务是减少文件的目标数组中返回$lookup
。 另外, $unwind
这里供应的实际目的被“合并”到$lookup
在服务器上执行的语句,所以这是典型的不只是抓住了结果数组的第一个元素更有效率。
可查询的群组加入
var query = entities.AsQueryable()
.Where(p => listNames.Contains(p.name))
.GroupJoin(
others.AsQueryable(),
p => p.id,
o => o.entity,
(p, o) => new { p.id, p.name, other = o.First() }
)
.OrderByDescending(p => p.other.name);
请求发送到服务器:
[
{ "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
{ "$lookup" : {
"from" : "others",
"localField" : "_id",
"foreignField" : "entity",
"as" : "o"
} },
{ "$project" : {
"id" : "$_id",
"name" : "$name",
"other" : { "$arrayElemAt" : [ "$o", 0 ] },
"_id" : 0
} },
{ "$sort" : { "other.name" : -1 } }
]
这几乎是相同的,但只是用不同的接口,并产生一个略有不同BSON语句,真的只有在功能语句简化命名的原因。 这确实带来了简单使用的另一种可能性$unwind
作为从生产SelectMany()
var query = entities.AsQueryable()
.Where(p => listNames.Contains(p.name))
.GroupJoin(
others.AsQueryable(),
p => p.id,
o => o.entity,
(p, o) => new { p.id, p.name, other = o }
)
.SelectMany(p => p.other, (p, other) => new { p.id, p.name, other })
.OrderByDescending(p => p.other.name);
请求发送到服务器:
[
{ "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
{ "$lookup" : {
"from" : "others",
"localField" : "_id",
"foreignField" : "entity",
"as" : "o"
}},
{ "$project" : {
"id" : "$_id",
"name" : "$name",
"other" : "$o",
"_id" : 0
} },
{ "$unwind" : "$other" },
{ "$project" : {
"id" : "$id",
"name" : "$name",
"other" : "$other",
"_id" : 0
}},
{ "$sort" : { "other.name" : -1 } }
]
通常放置$unwind
后直接$lookup
实际上是一个“优化模式”为聚合框架。 然而,.NET驱动程序通过迫使确实搞砸中,这一组合$project
之间,而不是使用的隐含命名"as"
。 如果不是为,这其实好过$arrayElemAt
当你知道你有“一”相关的结果。 如果你想在$unwind
“合并”,那么你的时候使用流畅的界面,或以不同的形式为以后更好的证明。
Querable自然
var query = from p in entities.AsQueryable()
where listNames.Contains(p.name)
join o in others.AsQueryable() on p.id equals o.entity into joined
select new { p.id, p.name, other = joined.First() }
into p
orderby p.other.name descending
select p;
请求发送到服务器:
[
{ "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
{ "$lookup" : {
"from" : "others",
"localField" : "_id",
"foreignField" : "entity",
"as" : "joined"
} },
{ "$project" : {
"id" : "$_id",
"name" : "$name",
"other" : { "$arrayElemAt" : [ "$joined", 0 ] },
"_id" : 0
} },
{ "$sort" : { "other.name" : -1 } }
]
所有非常熟悉,真的只是到功能命名。 正如使用$unwind
选项:
var query = from p in entities.AsQueryable()
where listNames.Contains(p.name)
join o in others.AsQueryable() on p.id equals o.entity into joined
from sub_o in joined.DefaultIfEmpty()
select new { p.id, p.name, other = sub_o }
into p
orderby p.other.name descending
select p;
请求发送到服务器:
[
{ "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
{ "$lookup" : {
"from" : "others",
"localField" : "_id",
"foreignField" : "entity",
"as" : "joined"
} },
{ "$unwind" : {
"path" : "$joined", "preserveNullAndEmptyArrays" : true
} },
{ "$project" : {
"id" : "$_id",
"name" : "$name",
"other" : "$joined",
"_id" : 0
} },
{ "$sort" : { "other.name" : -1 } }
]
这实际上是用“优化合并”的形式。 译者仍然坚持加入了$project
,因为我们需要的中间select
,以使语句有效。
摘要
因此,有相当多的方式基本上什么基本上是完全相同的结果相同的查询语句到达。 虽然你“可以”解析JSON到BsonDocument
形式和饲料这流利的Aggregate()
命令,它通常最好使用天然的建设者或LINQ接口,因为它们很容易地映射到相同的语句。
与选项$unwind
在很大程度上是示出,因为即使有一个“单数”匹配“聚结”的形式实际上是远更优化然后使用$arrayElemAt
取“第一”数组元素。 其中,这甚至成为与事情好像BSON限制的考虑更重要$lookup
目标阵列可能会导致父文档,而无需进一步的过滤超过16MB。 还有一个后在这里的匹配管道文件总结$查找总大小超过最大文件大小 ,我其实讨论如何避免这一限制,通过使用这样的选项或其他被击中Lookup()
只有在这个时候提供给流畅的界面语法。