如何精确匹配整个文档?

时间:2015-01-16 21:44:45

标签: mongodb

精确匹配的子文档很简单,但是有没有办法在集合中完全匹配整个文档?

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

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

3 个答案:

答案 0 :(得分:2)

我认为这不可能是彻头彻尾的,但可能的解决方案是散列文档。

保存时,始终创建文档的哈希值:

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);

然后在查询时,您可以通过哈希查询:

db.collection.find({
  hash: hash
})
如果您经常对文档进行原子更新,

可能会很烦人。

答案 1 :(得分:0)

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

请考虑以下事项:

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

所以现在你需要匹配"第三个"仅限文件。这是基本的代码概念:

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总是被排除在外,因为它是独一无二的。

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

一般查询参数将完成大部分工作,在这种情况下,将其缩小到两个文档,理想情况下使用索引来完成。匹配的其余部分由"蛮力"完成。 JavaScript评估,以便只有具有匹配签名的文档才能在查询中显示字段。

答案 2 :(得分:-1)

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

如果您想要没有某些字段的文档,可以使用 $ 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" }