8

我有两个现有集合,需要根据两个现有集合之间的比较来填充第三个集合。

需要比较的两个集合具有以下架构:

// 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)

在这种使用示例数据的情况下,我想返回一条记录,因为数据集合中的值大于设置集合中的高值。这可能使用 Mongo 查询或 map reduce,还是这种糟糕的集合结构(即,也许所有这些都应该在一个集合中)?

还有一些额外的说明:设置集合实际上应该每个“标识符”只有 1 条记录。数据集合将有每个“标识符”的许多记录。此过程可能一次扫描数十万份文档,因此资源考虑有些重要

4

4 回答 4

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,但它只适用于某些类型的数据和访问模式。

于 2013-11-06T17:52:25.313 回答
1

没有 JOIN 的概念,你必须改变你的方法并去规范化。

在您的情况下,看起来您正在执行数据日志验证。我的建议是循环设置集合,并且每个设置都使用findAndModify运算符,以便在匹配的数据收集记录上设置验证标志;之后,您可以在数据集合上使用 find 运算符,按新标志过滤。

于 2013-11-06T16:52:45.043 回答
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_CU
    • 将 s累加Value到一个数组中
    • Low通过操作累积s$mergeObjects以获得Lowis not的值null。使用 a$first是行不通的,因为这可能null首先需要(对于数据集合中的元素)。而在合并包含非空值的对象时$mergeObjects丢弃值。null
  • 然后丢弃Low值大于 150 的连接记录。

  • 最后通过$out阶段将结果记录输出到第三个集合。

于 2020-03-15T16:04:09.910 回答
0

我们开发的一项名为“数据比较和同步”的功能可能会在这里提供帮助。

它可以让您比较两个 MongoDB 集合并查看差异(例如,找出相同、缺失或不同的字段)。

然后,您可以将这些比较结果导出到 CSV 文件,并使用它来创建新的第三个集合。

将两个 MongoDB 集合中的差异导出到 CSV 文件

披露:我们是 MongoDB GUI、Studio 3T 的创建者。

于 2017-12-11T16:35:17.630 回答