比较两个MongoDB集合之间的文档

比较两个MongoDB集合之间的文档,mongodb,join,Mongodb,Join,我有两个现有集合,需要根据两个现有集合之间的比较填充第三个集合 需要比较的两个集合具有以下架构: // Settings collection: { "Identifier":"ABC123", "C":"1", "U":"V", "Low":116, "High":124, "ImportLogId":1 } // Data collection { "Identifier":"ABC123", "C":"1", "U":"V", "Date":"11

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

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

// 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)
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
    }
) 
{
    "_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
        }
    ]
}
选择s.标识符、r.ReadValue、r.U、r.C、r.Date
从设置
连接读码器
在s.Identifier=r.Identifier上
和s.C=r.C
s.U=r.U
式中(r.值=s.高)
在本例中,使用示例数据,我希望返回一条记录,因为数据集合的值大于设置集合的高值。是否可以使用Mongo查询或map reduce实现这一点,或者这是一个糟糕的集合结构(即,可能所有这些都应该在一个集合中)

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

如果没有连接的概念,您必须更改方法并取消规范化


在您的情况下,看起来您正在进行数据日志验证。我的建议是循环设置收集,每个设置都使用操作符,以便在匹配的数据收集记录上设置验证标志;之后,您可以在数据采集上使用find操作符,通过新标志进行过滤。

使用MongoDB执行类似操作没有好方法。如果您想要糟糕的方式,您可以使用如下代码:

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)
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
    }
) 
{
    "_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
        }
    ]
}
但不要期望它的性能甚至远比任何像样的RDBMS好

您可以重建架构并从数据收集中嵌入文档,如下所示:

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)
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
    }
) 
{
    "_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,但它只适用于特定类型的数据和访问模式

我们开发的一个功能名为,可能在这里有所帮助

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

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


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

Mongo 4.4
开始,我们可以通过新的聚合阶段和经典的
$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 } }
这:

  • 首先,通过新阶段将两个集合合并到管道中

  • 继续进行
    $group
    阶段,该阶段:

    • 根据
      Identifier
      C
      U
      对记录进行分组
    • s累积到数组中
    • 通过操作累积
      Low
      s,以获得一个非
      null
      Low
      值。使用
      $first
      将不起作用,因为这可能会先使用
      null
      (对于数据集合中的元素)。而
      $mergeObjects
      在合并包含非空值的对象时会丢弃
      null
  • 然后丢弃
    Low
    值大于150的合并记录

  • 最后通过stage将结果记录输出到第三个集合


为什么不使用diff命令?这是MongoDB真正不适合的类型。我们可以比较不同名称的集合吗?