Node.js 获取两个不同结构集合的差异
假设我有两个集合,Node.js 获取两个不同结构集合的差异,node.js,mongodb,aggregation-framework,Node.js,Mongodb,Aggregation Framework,假设我有两个集合,A和B A包含以下形式的简单文档: { _id: '...', value: 'A', data: '...' } { _id: '...', value: 'B', data: '...' } { _id: '...', value: 'C', data: '...' } … B包含如下嵌套对象: { _id: '...', values: [ 'A', 'B' ]} { _id: '...', values: [ 'C' ]} … 现在可能发生的情况是,A中的文档未被B
A
和B
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
中不存在
让我们称他们为“孤儿”
我现在的问题是:如何以最有效的方式找到这些孤立的文档?最后,我需要的是他们的\u id
字段
到目前为止,我已经使用了unwind
来“展平”A
,并使用计算了差异,但这需要相当长的时间,而且肯定不是真正有效的,因为我在客户端而不是在数据库中做所有工作
我已经看到MongoDB中有一个$setDifference
操作符,但我没有让它工作
有人能告诉我正确的方向吗?如何使用Node.js解决这个问题,并在数据库中运行大部分(全部?)工作?任何提示都非常感谢:-)在MongoDb中,您可以使用聚合管道进行尝试。如果这对您没有帮助,您可以使用MapReduce,但它有点复杂 对于本例,我将两个集合命名为“Tags”和“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是标量值(=不是列表)
屈服
{ "_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; });
返回:
{ "_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;
正如@karthigh.k所指出的那样,在命令中尝试一下:var myCursor=db.B.find();var B=myCursor.hasNext()?myCursor.next():null;db.A.find({value:{$nin:B.values}});希望如此helps@karthick.k把我冗长冗长的回答贴出来!你的解决方案看起来好多了!我将把我的放在这里,因为它展示了如何使用聚合管道…@cessor不同的想法和解决方案总是好的:)@karthigh.k基本上这应该是可行的,但我想知道这对于成千上万的文档来说是否是一个简单而有效的解决方案。这不是应该更声明性地表达的东西吗,这样数据库就可以自己决定如何运行查询了?@GoloRoden好的,但是试着对聚合和map reduce进行基准测试。我希望聚合技术在这种情况下速度较慢。首先:非常感谢您的详细回答:-)。我基本上明白了,除了为什么要在客户端而不是在数据库中计算设置差异。这可能吗?我是在命令行上做的。我看到,这是绝对没有必要这样做,因为最后的op评论显示。如果你想在某个地方自动运行它,我会尝试在map/reduce中实现它(假设你只是给出了你实际正在做的事情的峰值…)-因为你在twitter上问到聚合问题,我已经准备好这样做了,很多客户机/服务器来回地参与其中。。。这不是一个可行的解决方案,但可能是一个学习参考。。。
db.papers.find({'value' : {'$nin': tags.values }}, {'_id': 1})
var cursor = db.tags.find();
var tags = cursor.hasNext() : cusor.next() : null;