如何精确匹配整个文档?
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 评估完成,因此只有具有匹配签名的文档才能查询中的字段。
精确匹配子文档很容易,但是有没有办法精确匹配集合中的整个文档?
我有很多数据相似的文档,我只需要完全匹配,不需要额外的数据
使用负 $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 评估完成,因此只有具有匹配签名的文档才能查询中的字段。