c# - 编写查询以从特定文档结构的 mongo 获取信息
问题描述
想象一下我有这个文档结构:
DocumentOne
{
string Id { get; set; };
string InnerId { get; set; }
DocumentTwo[] InnerDocuments { get; set; }
}
DocumentTwo
{
string Id { get; set; }
string AnotherField { get; set; }
}
我尝试DocumentOne.InnerId != DocumentTwo.Id
使用 mongodb 驱动程序编写查询以在 .net 中按条件过滤文档。
我试着用
Builder<DocumentOne>.Filter.ElemMatch(x => x.InnerDocuments, y => y.Id != ???)
但我无法在此查询中访问 InnerId(问号)
如果我尝试使用 Fluent Syntax 之类的
database.Find(x => x.InnerDocuments.Contains(y => y.Id != x.InnerId))
或者
database.Find(!x => x.InnerDocuments.Any(y => y.Id != x.InnerId))
我收到来自驱动程序的错误消息。
我需要如何重写这个查询?
解决方案
有两种方法可以做到这一点,通过聚合或使用带有表达式的查找。
我们将看一下聚合,因为对我来说它更容易一些。
所以从你说的开始,我们将有 2 个 MongoDB 模型
public class DocumentOne
{
public string Id { get; set; }
public string InnerId { get; set; }
public DocumentTwo[] InnerDocuments { get; set; }
}
public class DocumentTwo
{
public string Id { get; set; }
public string AnotherField { get; set; }
}
然后,当我们展开内部文档时,我们需要第二个投影来跟踪后面的事情:
public class DocumentOneProjection
{
public string Id { get; set; }
public string InnerId { get; set; }
public DocumentTwo InnerDocuments { get; set; }
}
所以我们会把一些数据扔到 MongoDB 中来玩
var client = new MongoClient();
var database = client.GetDatabase("test");
var collection = database.GetCollection<DocumentOne>("documents");
await database.DropCollectionAsync(collection.CollectionNamespace.CollectionName);
await collection.InsertManyAsync(new[]
{
new DocumentOne()
{
Id = "1", InnerId = "10", InnerDocuments = new[]
{
new DocumentTwo()
{
Id = "11"
}
}
},
new DocumentOne()
{
Id = "2", InnerId = "20", InnerDocuments = new[]
{
new DocumentTwo()
{
Id = "20"
}
}
},
new DocumentOne()
{
Id = "3", InnerId = "30", InnerDocuments = new[]
{
new DocumentTwo()
{
Id = "30"
},
new DocumentTwo()
{
Id = "31"
}
}
}
});
然后我们就可以创建一个聚合查询
var items = await collection.Aggregate()
.Unwind(x => x.InnerDocuments)
.AppendStage<BsonDocument>(
@"{ $addFields: { matchInner: { $cmp: [ ""$InnerId"", ""$InnerDocuments._id"" ] } } }")
.Match("{ matchInner: { $ne : 0 } }") // 0 if the two values are equivalent.
.AppendStage<DocumentOneProjection>(
@"{ $unset: ""matchInner"" }")
.ToListAsync();
此查询从展开所有内部文档开始,这将为数组中的每个文档创建一个文档(https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/)
然后它创建一个新字段,我们稍后将创建一个匹配项,这使用比较($cmp - https://docs.mongodb.com/manual/reference/operator/aggregation/cmp/)
然后我们只匹配新字段,然后执行查询以取回文档。
推荐阅读
- javascript - Chart.js 主要刻度在使用 ticks.source 时未显示:类型上的“labels”:“timeseries”
- docker - 在 Docker 容器中运行的应用程序可以写入其容器的文件系统吗?
- android - 如何在 Paging 3 中使用网络绑定资源?
- angular - 在 ion-slides 中使用 Ionic 超级标签
- python - Python - 如何将数据转移到每个索引的开头
- c++ - 如何使 C++ 类的记录器易于使用
- python - 为什么 plt.figure() 和 tight_layout() 需要这么多时间来处理?
- android - 从媒体播放器获取当前位置抛出非法状态异常
- javascript - 如何使用类方法执行重试功能,同时保持输入
- ajax - ajax调用后部分视图变为空