Mongodb根据记录中的字段数进行查询
Mongodb Query based on number of fields in a record
我不太擅长在谷歌上搜索这个答案。
我有大约115个不同的字段,可能在每个记录中。Collection是一个巨大数据集上的mapreduce的输出。
看起来像这样:
{_id:'number1', value:{'a':1, 'b':2, 'f':5}},
{_id:'number2', value:{'e':2, 'f':114, 'h':12}},
{_id:'number3', value:{'i':2, 'j':22, 'z':12, 'za':111, 'zb':114}}
关于如何找到填充了5个字段的记录,有什么想法吗?
这仍然不是一个很好的查询,但有一种更现代的方法可以通过$objectToArray
和$redact
来实现
db.collection.aggregate([
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$size": { "$objectToArray": "$value" } },
3
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
其中$objectToArray
基本上将对象强制为数组形式,就像JavaScript中Object.keys()
和.map()
的组合一样。
这仍然不是一个好主意,因为它确实需要扫描整个集合,但至少聚合框架操作使用"本地代码",而不是像使用$where
那样使用JavaScript解释。
因此,为了进行最有效的查询操作,通常还是建议更改数据结构,尽可能使用自然数组以及存储的"大小"属性。
是的,这是可能的,但不是最好的方式。这是因为您实际上使用的是$where
运算符查询,该查询使用JavaScript求值来匹配内容。不是最有效的方法,因为这永远不能使用索引,并且需要测试所有文档:
db.collection.find({ "$where": "return Object.keys(this.value).length == 3" })
这将查找匹配"三个"元素的条件,然后只返回列出的两个文档:
{ "_id" : "number1", "value" : { "a" : 1, "b" : 2, "f" : 5 } }
{ "_id" : "number2", "value" : { "e" : 2, "f" : 114, "h" : 12 } }
或者,对于"五个"字段或更多字段,您可以执行大致相同的操作:
db.numbers.find({ "$where": "return Object.keys(this.value).length >= 5" })
因此,该运算符的参数实际上是在服务器上评估的JavaScript语句,以返回其中的true
。
更有效的方法是将元素的"计数"存储在文档本身中。通过这种方式,您可以"索引"该字段,查询效率更高,因为由其他条件选择的集合中的每个文档都不需要扫描来确定长度:
{_id:'number1', value:{'a':1, 'b':2, 'f':5} count: 3},
{_id:'number2', value:{'e':2, 'f':114, 'h':12}, count: 3},
{_id:'number3', value:{'i':2, 'j':22, 'z':12, 'za':111, 'zb':114}, count: 5}
然后,要获得包含"五个"元素的文档,您只需要简单的查询:
db.collection.find({ "count": 5 })
这通常是最理想的形式。但另一点是,MongoDB在一般情况下"玩得很好"的不是你可能从一般实践中满意的通用"对象"结构。问题是对象中元素的"遍历",这样一来,当您使用"数组"时,MongoDB会更快乐。即使是这种形式:
{
'_id': 'number1',
'values':[
{ 'key': 'a', 'value': 1 },
{ 'key': 'b', 'value': 2 },
{ 'key': 'f', 'value': 5 }
],
},
{
'_id': 'number2',
'values':[
{ 'key': 'e', 'value': 2 },
{ 'key': 'f', 'value': 114 },
{ 'key': 'h', 'value': 12 }
],
},
{
'_id':'number3',
'values': [
{ 'key': 'i', 'values': 2 },
{ 'key': 'j', 'values': 22 },
{ 'key': 'z'' 'values': :12 },
{ 'key': 'za', 'values': 111 },
{ 'key': 'zb', 'values': 114 }
]
}
因此,如果您真的切换到这样的"数组"格式,那么您可以使用$size
运算符的一个版本来执行精确的数组长度:
db.collection.find({ "values": { "$size": 5 } })
该运算符可以为数组长度的精确值工作,因为这是使用该运算符可以执行的操作的基本规定。你不能做的事情记录在"平等"比赛中。为此,您需要MongoDB的"聚合框架",它是JavaScript和mapReduce操作的更好替代方案:
db.collection.aggregate([
// Project a size of the array
{ "$project": {
"values": 1,
"size": { "$size": "$values" }
}},
// Match on that size
{ "$match": { "size": { "$gte": 5 } } },
// Project just the same fields
{{ "$project": {
"values": 1
}}
])
所以这些是候补。有一种"本机"方法可用于聚合和数组类型。但是,JavaScript评估也是MongoDB的"原生",只是没有在原生代码中实现,这一点是有争议的。
由于MongoDB版本3.6,您也可以使用$jsonSchema
(此处为文档):
db.getCollection('YOURCOLLECTION').find({
"$jsonSchema":{
"properties":{
"value":{"minProperties": 5}
}
}
})
- 如何从查询字符串中的输入字段发回文本
- 如何在 Meteor 中的 Mongo 查询中使用变量作为字段名称
- j查询检查复选框是否被选中,然后向输入字段添加值
- dojo.查询所需字段
- Mongoose,按填充字段对查询进行排序
- SQL查询-替换字段名称中的句点
- j查询验证单独的年、月、日的日期字段
- j查询各种字段添加,带有JSFiddle的可选复选框
- 对填充字段的 MongoDB 查询
- 隐藏字段值未显示在查询字符串中
- 查询MongoDB中不存在的字段
- 在控制台.log中显示查询的 [对象对象] 的字段
- j查询输入字段格式为 XX-XX-XX
- j查询添加必填项到输入字段
- 在MongoDB中动态查询字段
- GraphQL/中继模式”;无法查询字段&”;
- 如何在 where 子句中使用动态查询字段
- Mongodb查询字段的对象类型
- 传递嵌套文档查询字段
- 无法推断查询字段以在插入时设置错误