背景
最近客户端项目数据库替换成PouchDB(v7.2.2),在转移分页功能时遇到了问题。
场景
考虑性能和拓展空间,采用 db.allDocs()
作为批量查询方法,用skip
和limit
参数实现分页,例如:
let skipNum = 0;
db.allDocs({
limit: 50, // page size
skip: skipNum,
}).then(res => {
const { rows } = res;
......
skipNum += rows.length; // skip loaded data
});
});
首页加载异常,检查返回的rows
里包含了创建的索引
,原来是在之前测试时无意中创建了索引(db.createIndex()
),索引
的_id
以_design/idx-
开头,查询得知db.allDocs()
方法会返回数据库所有数据,且索引
也存储在业务数据”表“中,这就导致返回数据包含了`索引,不是期望的结果。
个人觉得
索引
这种业务无关数据不应该放入这张"表",违反直觉
那么删除索引,此时返回如预期一样,返回业务数据,并且最大数据按照limit
限制来返回。
如果搜索必须依赖索引,而索引与业务数据同一个数据库,怎么办呢?
这个数据库有另一个跟直觉相悖的地方,假定搜索字段必须要创建索引
才能实现,这次使用db.find()
来使用索引
。
let skipNum = 0;
// db内假定是如此[1,2,3,4,5],5条业务数据
db.createIndex({
index: {fields: ['_id']} // 对内部属性建立索引
}).then(function () {
/*
创建索引后,db内数据条数已经是6, 使用db.info()和db.allDocs()获取数据长度皆为6。
但是db.find()获取的长度还是5,看来已经过滤掉索引数据,很棒。
**/
return db.find({
selector: {_id: {$gt: null}},
limit: 50, // page size
skip: skipNum,
}).then(res => {
const { docs } = res.docs;
......
skipNum += docs.length; // skip loaded data
/*
dosc.length等于5,
所以加载下一页时,skipNum等于5,跳过5条,应该返回docs等于[]才是预期,可实际上?
**/
});
});
实际上返回一个包含一条数据的数组。猜想在skip
时,db.find()
方法还是把索引计入了。这就是上文返回重复的根本原因。
这非常让人迷惑,返回数据不含索引,但是
skip
跳过数据又计算了索引
。
结论
不使用索引或者只需要搜索内部属性_id
的,不需要db.createIndex()
,这样即使需要分页使用skip
也没有影响。
需要索引,且需要分页的,db.find()
不会返回索引
数据到结果中,但是注意skip
,在计算跳过的时候会计入索引
,在编写代码时如果遇到重复数据,需要留意了。