Mongodb查询基于记录中的字段数

时间:2014-10-09 15:08:54

标签: javascript mongodb mongodb-query pymongo

我不是很擅长谷歌搜索这个答案。

我有大约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个字段的记录的任何想法?

2 个答案:

答案 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}
      }
   }
})