【问题标题】:How do I compute the difference of two queries?如何计算两个查询的差异?
【发布时间】:2015-04-15 20:38:39
【问题描述】:

我有一个 MongoDB 集合,其中包含一组文档。每个文档都有一个 ISODate date 和一个整数 id(不是 _id)。如果集合中存在字段值为{ id: X, date: D } 的文档,则称id: X 存在date: D。所以,例如:

{ id: 1, date: 1/1/2000 }
{ id: 1, date: 1/2/2000 }
{ id: 1, date: 1/3/2000 }
{ id: 1, date: 1/4/2000 }
{ id: 2, date: 1/2/2000 }
{ id: 2, date: 1/3/2000 }
{ id: 3, date: 1/3/2000 }

我想随着时间的推移跟踪ids,因为它们每天被创建和销毁。使用上述数据,在 2000 年 1 月 1 日至 2000 年 1 月 4 日的日期范围内:

1/1/2000: id 1 is created
1/2/2000: id 2 is created
1/3/2000: id 3 is created
1/4/2000: id 2 is destroyed
1/4/2000: id 3 is destroyed

我认为解决此问题的最佳方法是每天循环,查看今天和第二天之间存在的ids,并执行一组差异。例如,要获取 2000 年 1 月 2 日创建和销毁的 id 集,我需要在任一天的数组之间执行两个集差异:

var A = [ <ids that exist on 1/1/2000> ];
var B = [ <ids that exist on 1/2/2000> ];
var created_set = set_difference(B, A); // Those in B and not in A
var destroyed_set = set_difference(A, B); // Those in A and not in B

我可以使用find() 命令获取AB 的游标,但我不知道如何在两个游标之间执行set_difference

我的另一个选择是使用聚合管道,但我无法考虑如何以可以使用 $setDifference 运算符的方式来制定管道。

作为一名 MongoDB 新手,我确信我正在以错误的方式思考问题。当然,这是可以做到的吗?我错过了什么?

【问题讨论】:

  • 你的目标到底是什么?找出两个日期之间发生的所有变化?生成所有更改过的列表?
  • @jtmarmon 我的目标是为集合中找到的每个 ID 号生成创建和销毁日期的列表。上面的第二个数据列表显示了各种 id 的创建和销毁时间,这就是我所追求的。
  • 日期是 ISODate 格式吗?
  • @chridam 是的,日期是 ISODate,我会用这个细节更新问题。
  • 您为什么不简单地在客户端代码中解决这个问题,或者在编写更新时解决这个问题,而不是在读取时解决?在读取时执行此操作有点违反 MongoDB 哲学。如果这些游标位于不同的分片、不同的大陆或大小为 TB 怎么办?

标签: mongodb mongodb-query aggregation-framework set-difference


【解决方案1】:
db.mystuff.aggregate([
    {$group: {_id: '$id', created: {$first: '$date'}, destroyed: {$last: '$date'}}}
])

【讨论】:

  • 天哪,太棒了。
  • @mnemosyn 这可能是真的,但就我的目的而言,id 将恰好存在于一个连续的日期块中。
  • @mnemosyn 出于好奇,你能举个例子以及为什么这不适用于间隙
  • @jtmarmon:嗯,它不会找到间隙,只找到第一个创建和最后一个销毁的,即它找不到A...B, C...D, E...F,但它只会找到A...F(自然,因为您需要可以为每个 id 输出日期对列表的东西)。但显然,这不是 OP 所要寻找的,而且这相当短而且有点优雅......
  • 哦,我明白了。这是假设每个日期都是一个事件 - 我只是假设第一个 = 创建,最后一个 = 销毁。明白了,谢谢
【解决方案2】:

假设您有以下样本集合:

db.collection.insert([
    { id: 1, date: ISODate("2000-01-01") },
    { id: 1, date: ISODate("2000-01-02") },
    { id: 1, date: ISODate("2000-01-03") },
    { id: 1, date: ISODate("2000-01-04") },
    { id: 2, date: ISODate("2000-01-02") },
    { id: 2, date: ISODate("2000-01-03") },
    { id: 3, date: ISODate("2000-01-03") }
]);

以下聚合将为您提供一些使用 $setDifference 运算符尝试实现的方向:

var start = new Date(2000, 0, 1);
var end = new Date(2000, 0, 2)
db.collection.aggregate([
    {
        "$match":{
            "date": {
                "$gte": start, 
                "$lte": end 
            }
        }
    },
    {
        $group: {
            _id: "$date",            
            "A": {
                "$addToSet": {
                    "$cond": [
                        { "$eq": [ "$date", start ] },
                        "$id",
                        false
                    ]
                }
            },
            "B": {
                "$addToSet": {
                    "$cond": [
                        { "$eq": [ "$date", end ] },
                        "$id",
                        false
                    ]
                }
            }
        }
    },
    { 
        "$project": {
            "A": {
                "$setDifference": [ "$A", [false] ]
            },
            "B": {
                "$setDifference": [ "$B", [false] ]
            }
        }
    },
    { 
        "$project": {
            "_id": 0,
            "date": "$_id",
            "created_set": {
                "$setDifference": [ "$B", "$A" ]
            },
            "destroyed_set": {
                "$setDifference": [ "$A", "$B" ]
            }
        }
    }
]);

输出

{
    "result" : [ 
        {
            "date" : ISODate("2000-01-02T00:00:00.000Z"),
            "created_set" : [2, 1],
            "destroyed_set" : []
        }, 
        {
            "date" : ISODate("2000-01-01T00:00:00.000Z"),
            "created_set" : [],
            "destroyed_set" : [1]
        }
    ],
    "ok" : 1
}

【讨论】:

  • 这与我所寻找的很接近 - 在两个不同日期之间来来往往的简明 ID 集。
猜你喜欢
  • 1970-01-01
  • 2019-06-27
  • 1970-01-01
  • 2021-06-16
  • 2010-10-29
  • 2011-05-21
  • 2010-10-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多