在 MongoDB 中搜索任何字段的值而不显式命名它
Posted
技术标签:
【中文标题】在 MongoDB 中搜索任何字段的值而不显式命名它【英文标题】:Searching for value of any field in MongoDB without explicitly naming it 【发布时间】:2011-10-11 01:46:25 【问题描述】:我查看了 MongoDB 文档并在 Google 上搜索了这个问题,但找不到合适的答案。所以,这就是我要找的。 假设我有一个包含这样元素的集合:
"foo" : "bar",
"test" : "test",
"key" : "value",
我想要实现的是通过在所有(可能除了有限多个 ;-) )字段中搜索来找到一个元素。换句话说:给定一个查询,我不知道应该在哪个字段中找到查询。
在我看来是这样的
db.things.find(_ANY_ : "bar")
会给我示例元素。
感谢您的帮助。
【问题讨论】:
所以,您需要的是全文搜索,这在 mongodb 中没有原生实现,另请参阅:mongodb.org/display/DOCS/Full+Text+Search+in+Mongo 我不认为这是一个文本搜索问题。它是按值查询。他们都分享了这样一个事实,即在 mongo 中没有对它的原生支持;) @asaaki:与此同时,Mongo 已经实现了full-text search。让我们删除我们的 cmets。 【参考方案1】:This answer 对类似问题有您的解决方案,为了完整起见,我将在此重复。您可以使用$where
运算符在 MongoDB 服务器上运行任意 javascript,但需要注意的是这将比几乎任何其他类型的查询慢得多。对于您的示例,它将是:
db.things.find($where: function()
for (var key in this)
if (this[key] === "bar")
return true;
return false;
);
【讨论】:
return false;
应该是进一步向下的一个括号
"在 3.6 版中更改:$expr 运算符允许在查询语言中使用聚合表达式。$expr 比 $where 更快,因为它不执行 JavaScript,应尽可能首选。" - Source【参考方案2】:
遗憾的是,之前的答案都没有解决 mongo 可以在数组或嵌套对象中包含嵌套值的事实。
这是正确的查询:
$where: function()
var deepIterate = function (obj, value)
for (var field in obj)
if (obj[field] == value)
return true;
var found = false;
if ( typeof obj[field] === 'object')
found = deepIterate(obj[field], value)
if (found) return true;
return false;
;
return deepIterate(this, "573c79aef4ef4b9a9523028f")
由于在数组或嵌套对象上调用 typeof 将返回“对象”,这意味着查询将迭代所有嵌套元素,并将遍历所有元素,直到找到具有值的键。
您可以使用嵌套值检查以前的答案,结果将远非预期。
对整个对象进行字符串化的性能要差得多,因为它必须逐个遍历所有内存扇区以尝试匹配它们。并在 ram 内存中创建对象的副本作为字符串(由于查询使用更多的 ram,效率低下,因为函数上下文已经加载了对象)
【讨论】:
我们可以重写 if (obj[field] == value) 比如 -- if(typeof obj[field] == 'string' && obj[field].contains(/value/))。它提供了更准确的搜索结果 @LokeshBoran 它给了我这个错误 TypeError: Invalid type: first can't be a Regular Expression :\ndeepIterate@:4:49\ndeepIterate@:9:25\n@:15:12 \n @prakharjain 你能把你的代码贴在一个粘贴箱里吗?那么我们可以看看吗?【参考方案3】:使用$where 和做全表扫描一样,不能使用索引。我也无法让它工作,但我确实发现它有效(它也相当于全表扫描):
db.collection.find().forEach(function(doc)
for (var key in doc)
if ( /needle/.test(doc[key]) )
printjson(doc);
);
其中/needle/
是在doc[key]
的值中查找的正则表达式
【讨论】:
【参考方案4】:要对所有字段进行文本搜索,首先必须在所有字段上创建文本索引。
正如mongodb documentation 所指出的,“要允许对所有具有字符串内容的字段进行文本搜索,请使用通配符说明符 ($**) 来索引所有包含字符串内容的字段。”
如果您在 mongo shell 中工作(通过调用 'mongo' 从命令行执行),那么您可以使用此命令执行此操作,其中 'collection' 是您想要的 db 中集合的名称使用。
db.collection.createIndex( "$**": "text" , name: "TextIndex" )
第二个对象,即name:"TextIndex"
,是可选的...您实际上不需要为索引命名,因为每个集合只能有一个文本索引(一次...您可以如果需要,可以删除索引并创建新索引)。
在所有字段上创建文本索引后,您可以使用以下查询对象进行简单的文本搜索:
$text : $search: <your string>
所以,如果您正在编写一个 javascript 函数,您可能会执行以下操作:
var cursor = db.collection(<collection_name>).find( $text: $search: <your string> );
有关控制搜索的各种方法的更多信息,请参阅有关文本搜索的 mongodb 文档here
【讨论】:
如果字符串已经转义了围绕一个单词的 \"s,那么它会将搜索变成一个 'and' 搜索而不是 'or' 搜索。 $text : $search: "\"jim \" \"habit\"" 在文本索引中查找所有带有 'jim' 和 'habit' 的记录。 @dave-adelson 如何使用正则表达式?我试图在其中使用正则表达式,但它给出了异常“errmsg”:“\”$search\”的类型错误。预期的字符串,找到了正则表达式”,查询:find($text:$search:/version/ )【参考方案5】:要进行文本搜索,您必须为您的收藏创建文本索引。 有关更多信息,请查看 mongo 文档:indexes text
【讨论】:
【参考方案6】:你可以用递归函数来做到这一点:
var recursiveSearch = function(query)
db.test_insert.find().forEach(function(items)
var i = 0;
var recursiveFunc = function(itemsArray, itemKey)
var itemValue = itemsArray[itemKey];
if(itemValue === query)
printjson(items);
if(typeof itemValue === "object")
Object.keys(itemValue).forEach(function(itemValueKey)
recursiveFunc(itemValue, itemValueKey);
);
;
Object.keys(items).forEach(function(item)
recursiveFunc(items, item);
);
);
;
recursiveSearch('your string');
【讨论】:
【参考方案7】:如果不单独检查应用程序端的文档或通过服务器端的代码执行,这是不可能的。考虑将架构更改为:
params:[field:"foo", value:"bar", field:"test", value:"test", field:"key", value:"value"]
这显然有一些缺点(主要是性能和污染模式),但可以满足您的需求:
db.things.find('params.value':"bar")
【讨论】:
如何使用此架构按特定字段排序?我的意思是像 .sort(foo: 1) 在 OP 中的。 你没有。 find('params.field':"foo").sort('params.value':1) 不等价,因为数组排序的工作方式。 我们如何为 Spring Data mongo 查询编写存储库方法?请帮帮我..谢谢,Neha 全文搜索更简单。 这似乎与 dave adelson 的最高投票答案相矛盾。那是因为这个答案已经过时了吗?或者当您说“服务器端代码执行”时,您指的是创建索引吗?或者您是否建议该选项受到限制,因为它只搜索文本而不搜索其他类型?以上是关于在 MongoDB 中搜索任何字段的值而不显式命名它的主要内容,如果未能解决你的问题,请参考以下文章
在 Sencha Touch 中设置 numberfield 的值而不触发“change”事件
如何在 django(DRF)中检索对象列表(包括 ForeignKey 字段数据)而不显着增加数据库调用时间