精确匹配的子文档很简单,但是有没有办法在集合中完全匹配整个文档?
我有很多类似数据的文档,我只需要完全匹配而没有额外的数据
使用否定$ exists对我来说不起作用,因为我事先并不知道所有可能的字段。
答案 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" }