获取两个不同结构集合的差异



假设我有两个集合,AB

A包含以下形式的简单文档:

{ _id: '...', value: 'A', data: '...' }
{ _id: '...', value: 'B', data: '...' }
{ _id: '...', value: 'C', data: '...' }
…

B包含如下嵌套对象:

{ _id: '...', values: [ 'A', 'B' ]}
{ _id: '...', values: [ 'C' ]}
…

现在可能发生的情况是,A中的某些文档没有被B中的任何文档引用,或者B中的某些引用文档在A中不存在。

让我们称他们为"孤儿"。

我现在的问题是:如何以最有效的方式找到那些孤立的文档?最后,我需要的是他们的_id字段。

到目前为止,我已经使用unwind来"压平"A,并使用Ramda的differenceWith函数计算差异,但这需要相当长的时间,而且肯定不是很有效,因为我在客户端而不是在数据库中完成所有工作。

我看到MongoDB中有一个$setDifference操作符,但我没有让它工作。

有人能告诉我正确的方向吗?如何使用Node.js解决这个问题,并在数据库中运行大部分(全部?)工作?欢迎任何提示:-)

在MongoDb中,您可以使用聚合管道进行尝试。如果这没有帮助,您可以使用MapReduce,但它有点复杂。

在这个例子中,我将这两个集合命名为"Tags"one_answers"Papers",其中Tags在你的例子中被命名为"B",Papers将是"A"。

首先,我们得到一组实际存在并引用文档的值。为此,我们将标签集合中的每个值压平,然后将其打包在一起。展开将为"values"数组中的每个值创建一个具有原始_id的文档。然后,这个平面列表会被重新收集,而他们的id会被忽略。

 var referenced_tags = db.tags.aggregate(
     {$unwind: '$values'},
     {$group: {
         _id: '', 
         tags: { $push: '$values'}
     }
 });

返回:

{ "_id" : "", "tags" : [ "A", "B", "C"] }

此列表是所有文档中所有值的集合。

然后,创建一个类似的集合,其中包含可用文档的一组标记。这不需要展开步骤,因为_id是标量值(=不是列表)

var papers = db.papers.aggregate(
    {$group: { 
        _id: '', 
        tags: {$push: '$value'}
    }
});

产生

{ "_id" : "", "tags" : [ "A", "B", "C", "D"] }

正如您已经看到的,从我放入数据库的集合中,a中似乎有一个id为"D"的文档(纸张),它在标记集合中没有被引用,因此是孤立的。

你现在可以用任何你喜欢的方式计算差值集,这可能很慢,但适合作为一个例子:

var a = referenced_tags.tags;
var b = tags.tags;
var delta = a.filter(function (v) { return b.indexOf(v) < 0; });

下一步,您可以通过在delta中查找这些值并仅投影它们的id来找到id:

db.papers.find({'value' : {'$in': delta}}, {'_id': 1})

返回:

{ "_id" : ObjectId("558bd2...44f6a") }

编辑:虽然这很好地展示了如何使用聚合框架来处理这个问题,但这不是一个可行的解决方案。甚至不需要聚合,因为MongoDb非常聪明:

db.papers.find({'value' : {'$nin': tags.values }}, {'_id': 1})

标签在哪里

var cursor = db.tags.find();
var tags = cursor.hasNext() : cusor.next() : null;

正如@karthick.k 所指出的

相关内容

  • 没有找到相关文章

最新更新