获得两个不同结构的集合的区别
假设我有两个集合, A
和B
A
包含以下forms的简单文档:
{ _id: '...', value: 'A', data: '...' } { _id: '...', value: 'B', data: '...' } { _id: '...', value: 'C', data: '...' } …
B
包含这样的嵌套对象:
{ _id: '...', values: [ 'A', 'B' ]} { _id: '...', values: [ 'C' ]} …
现在可能发生的情况是, A
中有文档没有被B
的任何文档引用,或者B
中有引用的文档在B
中不存在。
我们称他们为“孤儿”。
我现在的问题是:如何以最有效的方式find那些孤儿文件? 最后,我需要的是他们的_id
领域。
到目前为止,我已经使用unwind
来“扁平化” A
,并使用lambda的differenceWith
函数来计算差异,但这需要相当长的时间,并且肯定不是很有效,因为我在客户端上完成所有工作,而不是在数据库。
我已经看到,在MongoDB中有一个$setDifference
运算符,但我没有得到它的工作。
任何人都可以指出我正确的方向,如何使用Node.js解决这个问题,并在数据库中运行大部分(所有?)工作? 任何提示都表示赞赏:-)
在MongoDb中,您可以使用您正在尝试的聚合pipe道。 如果这没有帮助你可以使用MapReduce,但它有点复杂。
在这个例子中,我命名了两个集合“Tags”和“Papers”,其中标签在您的示例中被命名为“B”,并且Papers将是“A”。
首先,我们得到一组实际存在的值,并引用文档。 为此,我们将标签集合中的每个值拼合起来,并将其打包在一起。 展开使用“values”数组中每个值的原始_id创build一个文档。 这个平面列表然后重新收集,他们的ID被忽略。
var referenced_tags = db.tags.aggregate( {$unwind: '$values'}, {$group: { _id: '', tags: { $push: '$values'} } });
这返回:
{ "_id" : "", "tags" : [ "A", "B", "C"] }
该列表是所有文档中所有值的集合。
然后,创build一个类似的集合,包含可用文档的一组标签。 这不需要展开步骤,因为_id是标量值(=不是列表)
var papers = db.papers.aggregate( {$group: { _id: '', tags: {$push: '$value'} } });
生产
{ "_id" : "", "tags" : [ "A", "B", "C", "D"] }
正如您已经看到的那样,从我放入数据库的集合中,似乎在A中有一个ID为“D”的Document(Paper),它在tags集合中没有被引用,并且在orrhan之前。
你现在可以用你喜欢的任何方式来计算差异,这可能会很慢,但是适合作为一个例子:
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") }
编辑:虽然这很好地展示了如何用聚合框架来解决这个问题,但这不是一个可行的解决scheme。 一个甚至不需要聚合,因为MongoDb非常聪明:
db.papers.find({'value' : {'$nin': tags.values }}, {'_id': 1})
标签在哪里
var cursor = db.tags.find(); var tags = cursor.hasNext() : cusor.next() : null;
正如@ karthick.k所指出的那样