浮生逆旅

Mongodb之$where踩坑

字数统计: 479阅读时长: 1 min
2019/11/06 Share

缘由

今天在写一个业务功能的时候,业务实体的某个属性为一个数组,我的其中一个过滤条件为数组长度小于等于某个值

尝试与问题

$size

首先我使用了 $size

1
2
3
4
5
6
7
db.mission_task_types.find({
workflow: {
$size: {
$lte: 6
}
}
});

但,我得到了这个

1
2
3
4
5
6
7
{
"message" : "$size needs a number",
"waitedMS" : "0",
"ok" : 0,
"code" : 2,
"name" : "MongoError"
}

到现在我才发现,$size 的 value 只接收一个具体的数值,而不能使用范围值


$where

$size 失败了,决定使用不能够利用索引的 $where

1
2
3
db.mission_task_types.find({
$where: "this.workflow.length <= 6"
});

但,我得到了这个

1
2
3
4
5
6
7
8
{
"message" : "TypeError: this.workflow is undefined :" +
"_funcs7@:1:24" +
"",
"ok" : 0,
"code" : 139,
"name" : "MongoError"
}

why?

为什么跟我说 workflow 是 undefined?经过一番折腾,最终我发现了集合中有这么个玩意

1
2
3
{
"_id" : ObjectId("5dc2a39150b883b8ba1e93c6")
}

突然我明白了,明白了是因为我知道是这个只有 _id 的脏数据导致我得到了这个错误,于是我将查询语句修改了下

1
2
3
db.mission_task_types.find({
$where: "this.workflow && this.workflow.length <= 6"
});

啊哈,果然!因为脏数据中不存在 workflow 属性,而 $where 的 value 接收的是 JavaScript 的表达式,当 workflow 属性不存在时,调用这个不存在属性的 length 属性时,就抛异常了

注意:因为 $where 不能够使用索引,所以如果一定要使用 $where 时,若有其他查询条件可以利用到索引,请将这些查询条件放到 $where 前面


后记

在我浏览别的博主的文章时,我发现了更高效的方法,那就是使用 $exists 来判断某个数组下标的元素存不存在

例如,查询出数组长度小于等于 6 的

1
2
3
4
5
db.mission_task_types.find({
"workflow.6": {
$exists: false
}
});

若大家有相似需求,推荐使用这种查询方式

拜~


CATALOG
  1. 1. 缘由
  2. 2. 尝试与问题
    1. 2.1. $size
    2. 2.2. $where
  3. 3. 后记