如何精确匹配整个文档?

How to exact match entire document?

精确匹配子文档很容易,但是有没有办法精确匹配集合中的整个文档?

我有很多数据相似的文档,我只需要完全匹配,不需要额外的数据

使用负 $exists 对我不起作用,因为我事先不知道所有可能的字段。

我真的不明白你的问题,你能解释一下吗?

如果您想要没有某些字段的文档,您可以使用 $exists.

例如,如果您有...

{a: 1 , b: "1", c: true }
{a: 2, b: "2", c: false}
{a: null, b: "3" }

然后db.my_collection.find({a: {$exists: true}});找到

{a: 1 , b: "1", c: true }
{a: 2, b: "2", c: false}

并且 db.my_collection.find({a: {$exists: false}}); 发现

{a: null, b: "3" }

我不认为这是完全可能的,但一个可能的解决方案是散列文档。

保存时,始终创建文档的散列:

var doc = {};
delete doc.hash; // never include the hash itself in the calculation
doc.hash = crypto.createHash('sha256').update(JSON.stringify(doc)).digest();
db.collection.insert(doc);

那么查询的时候可以通过hash查询:

db.collection.find({
  hash: hash
})

如果您经常对文档进行原子更新,可能会很烦人。

这不是一个理想的方法,但真正在服务器上过滤掉它的唯一方法是使用 JavaScript 对 $where 运算符的评估。确保它与传统查询一起使用,至少可以从索引选择中获得一些性能优势,因为 JavaScript 本身无法做到这一点。

考虑以下因素:

{ "a" : 1 }
{ "a" : 1, "b" : 2 }
{ "a" : 1, "b" : 2, "c" : 3 }
{ "a" : 1, "b" : 2, "c" : 3, "d" : 4 }

所以现在您只需要匹配 "third" 文档。这是基本的代码概念:

var query = { "a": 1, "b": 2, "c": 3 };
var string =  "";

Object.keys(query).forEach(function(key) {
    if (query[key].constructor.toString().match(/(Array|Object)/) == null) 
        string += key + query[key].valueOf().toString();
});

query['$where'] = 'function() { ' +
    'var compare =  ""; ' +
    'var string = "' + string + '"; ' +

    'var doc = this; ' +
    'delete doc._id; ' +

    'Object.keys(doc).forEach(function(key) { ' +
        'if (doc[key].contructor.toString().match(/(Array|Object)/) == null) ||' +
          'compare += key + doc[key].valueOf().toString(); ' +
    '}); ' +
    'return compare == string; ' +
'};';

db.test.find(query);

一些驱动程序对于将外部变量混合到代码中有更好的概念,但它给出了基本的想法。

您需要根据所需的确切字段和值计算外部图片或散列,然后在服务器上使用相同的方法根据当前文档字段进行计算。自然 _id 总是被排除在外,因为它是唯一的。

您不需要子元素的签名,因为正如您所说,您可以 "exact match" 那些纯粹在查询中。所以这只是将那些人排除在比较一代之外的问题。

一般查询参数将完成大部分工作,在本例中将其缩小到两个文档,最好使用索引来完成。其余匹配由 "brute force" JavaScript 评估完成,因此只有具有匹配签名的文档才能查询中的字段。