这仍然不是一个好的查询方式,但是可以通过$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" })
这个条件是寻找匹配"three"元素的情况,然后只返回你列出的文件中的两个:
{ "_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" })
因此,该运算符的参数实际上是在服务器上评估以返回为true
的JavaScript语句。
一种更有效的方法是将文档中元素的“计数”存储在文档本身中。通过这种方式,您可以对此字段进行“索引”,查询更加高效,因为不需要扫描集合中满足其他条件的每个文档以确定长度:
{_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": {
"values": 1,
"size": { "$size": "$values" }
}},
{ "$match": { "size": { "$gte": 5 } } },
{{ "$project": {
"values": 1
}}
])
这些是备选方案。对于聚合和数组类型,有一个“本地”方法可用。但是可以认为JavaScript评估在MongoDB中也是“本地”的,只是没有在本地代码中实现。