我不是很擅长谷歌搜索这个答案。
我有大约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个字段的记录的任何想法?
答案 0 :(得分:3)
它仍然不是一个很好的查询,但有一种更现代的方法可以通过$objectToArray
和$redact
db.collection.aggregate([
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$size": { "$objectToArray": "$value" } },
3
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
$objectToArray
基本上将对象强制转换为数组形式,就像JavaScript中Object.keys()
和.map()
的组合一样。
它仍然不是一个奇妙的想法,因为它确实需要扫描整个集合,但至少聚合框架操作使用"本机代码"与使用$where
的情况下的JavaScript解释相反。
因此,通常建议更改数据结构并使用自然数组以及存储的" size"尽可能使用属性以便进行最有效的查询操作。
是的,有可能做到但不是最好的方式。这样做的原因是您实际上使用$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评估也是" native"到MongoDB,因此没有在本机代码中实现。
答案 1 :(得分:0)
自 MongoDB 3.6 版起,您还可以为此使用 $jsonSchema
(here's the documentation):
db.getCollection('YOURCOLLECTION').find({
"$jsonSchema":{
"properties":{
"value":{"minProperties": 5}
}
}
})