我有两个现有的集合,需要根据两个现有集合之间的比较来填充第三个集合。需要比较的两个集合具有以下模式:
Settings collection
{
"Identifier":"ABC123",
"C":"1",
"U":"V",
"Low":116,
"High":124,
"ImportLogId":1
}
Data collection
{
"Identifier":"ABC123",
"C":"1",
"U":"V",
"Date":"11/6/2013 12AM",
"Value":128,
"ImportLogId": 1
}
我是MongoDB和NoSQL的新手,所以我很难掌握如何做到这一点。 SQL看起来像这样
SELECT s.Identifier, r.ReadValue, r.U, r.C, r.Date
FROM Settings s
JOIN Reads r
ON s.Identifier = r.Identifier
AND s.C = r.C
AND s.U = r.U
WHERE (r.Value <= s.Low OR r.Value >= s.High)
在这种情况下使用示例数据,我想返回一条记录,因为Data集合中的值大于设置集合中的高值。这可能是使用Mongo查询或map reduce,还是这个糟糕的集合结构(也许所有这些都应该在一个集合中)?
还有一些补充说明: Settings集合中每个“Identifier”实际上只有1条记录。每个“标识符”的数据集合将包含许多记录。这个过程可能同时扫描数十万个文档,因此资源考虑有点重要
答案 0 :(得分:3)
没有使用MongoDB执行此类操作的好方法。如果您想要 BAD 方式,可以使用以下代码:
db.settings.find().forEach(
function(doc) {
data = db.data.find({
Identifier: doc.Idendtifier,
C: doc.C,
U: doc.U,
$or: [{Value: {$lte: doc.Low}}, {Value: {$gte: doc.High}}]
}).toArray();
// Do what you need
}
)
但不要指望它会像任何体面的RDBMS一样远程执行。
您可以重建架构并从数据收集中嵌入文档,如下所示:
{
"_id" : ObjectId("527a7f4b07c17a1f8ad009d2"),
"Identifier" : "ABC123",
"C" : "1",
"U" : "V",
"Low" : 116,
"High" : 124,
"ImportLogId" : 1,
"Data" : [
{
"Date" : ISODate("2013-11-06T00:00:00Z"),
"Value" : 128
},
{
"Date" : ISODate("2013-10-09T00:00:00Z"),
"Value" : 99
}
]
}
如果嵌入式文档的数量很少,但是说实话,使用文档数组远远不是愉快的体验。甚至没有提到随着数据阵列的大小增加,您可以轻松地达到文档大小限制。
如果这种操作是您的应用程序的典型操作,我会考虑使用不同的解决方案。尽管我喜欢MongoDB,但它只适用于某些类型的数据和访问模式。
答案 1 :(得分:1)
如果没有JOIN的概念,你必须改变你的方法并进行反规范化。
在您的情况下,看起来您正在进行数据日志验证。我的建议是循环设置集合,并且每个都使用findAndModify运算符,以便在匹配的数据集合记录上设置验证标志;之后,您可以在数据集合上使用find运算符,按新标志进行过滤。
答案 2 :(得分:1)
从Mongo 4.4
开始,我们可以通过新的$unionWith
聚合阶段以及经典的$group
阶段来实现这种“联接”:
// > db.settings.find()
// { "Identifier" : "ABC123", "C" : "1", "U" : "V", "Low" : 116 }
// { "Identifier" : "DEF456", "C" : "1", "U" : "W", "Low" : 416 }
// { "Identifier" : "GHI789", "C" : "1", "U" : "W", "Low" : 142 }
// > db.data.find()
// { "Identifier" : "ABC123", "C" : "1", "U" : "V", "Value" : 14 }
// { "Identifier" : "GHI789", "C" : "1", "U" : "W", "Value" : 43 }
// { "Identifier" : "ABC123", "C" : "1", "U" : "V", "Value" : 45 }
// { "Identifier" : "DEF456", "C" : "1", "U" : "W", "Value" : 8 }
db.data.aggregate([
{ $unionWith: "settings" },
{ $group: {
_id: { Identifier: "$Identifier", C: "$C", U: "$U" },
Values: { $push: "$Value" },
Low: { $mergeObjects: { v: "$Low" } }
}},
{ $match: { "Low.v": { $lt: 150 } } },
{ $out: "result-collection" }
])
// > db.result-collection.find()
// { _id: { Identifier: "ABC123", C: "1", U: "V" }, Values: [14, 45], Low: { v: 116 } }
// { _id: { Identifier: "GHI789", C: "1", U: "W" }, Values: [43], Low: { v: 142 } }
此:
首先通过新的$unionWith
阶段将两个集合并入管道。
继续执行$group
阶段:
Identifier
,C
和U
的记录分组Value
s累积到一个数组中$mergeObjects
操作累积Low
,以获得不是Low
的{{1}}值。使用null
无效,因为这可能首先需要$first
(对于数据收集中的元素)。合并包含非空值的对象时,null
会丢弃$mergeObjects
值。然后丢弃null
值大于150的联接记录。
最后通过$out
阶段将结果记录输出到第三集合。
答案 3 :(得分:0)
我们开发的名为Data Compare & Sync的功能可能会对此有所帮助。
它允许您比较两个MongoDB集合并查看差异(例如,发现相同,缺失或不同的字段)。
然后,您可以将这些比较结果导出到CSV文件,并使用它创建新的第三个集合。
披露:我们是MongoDB GUI的创建者,Studio 3T。