一直在探索 pouch db 的使用,因此我们可以利用它的离线同步而不是自己做。我们有一个 cordova 应用程序,它从 REST API 中提取数据并将其保存到 Web sql 存储中。其中一部分是各种商店的大约 5000 个物理位置。我在 cordova 应用程序上计时,我们在大约 11 秒内下载商店并保存它们,以及另一个项目信息请求。仅将这 5k 条记录保存为 pouch db 中的文档就需要 30 秒。不计算请求时间。
这是我的做法:
let db = PouchProxy.getDB();
this.render("loading", { message: "Saving locations" });
// stores from api
let stores = res.stores;
let docs = [];
// check for saved stores, checking ids that start with store_
db.allDocs({ include_docs: true, startkey: 'store_', endkey: 'store_\uffff' }).then((results) => {
// go through saved stores
for (let row of results.rows) {
let doc = row.doc;
// get the number id. The _id is simply 'store_idnumfromapi'
let id = parseFloat(doc._id.split('store_')[1]);
if (isNaN(id)) {
throw "Cannot be NaN";
}
// iterate through stores from api
for (var i = 0; i < stores.length; i++) {
let store = stores[i];
// find store and local record
if (store.id === id) {
// sets the _id and other properties from the store api object to a new object
let map = PouchProxy.storeToDocMap(store);
// set revision
map._rev = doc._rev;
docs.push(map);
stores.splice(i, 1);
break;
}
}
}
// go through remaining stores and push to docs set
for (let store of stores) {
docs.push(PouchProxy.storeToDocMap(store));
}
// save all the things
console.log(Date.now());
return db.bulkDocs(docs);
}).then(() => {
// this the second time stamp i use to get the 30 seconds
console.log(Date.now());
// calculate geolocation stuff
for (let store of docs) {
store.distance = this.distanceBetweenPoints(store, { lat: position.coords.latitude, long: position.coords.longitude });
}
docs.sort((a, b) => {
return b.distance - a.distance;
});
this.render("store-list", { stores: docs.slice(0, 19) });
}).catch(function (err) {
console.log(err);
});
希望代码足够清晰。我考虑过为商店切换到一个文档,但后来我觉得单独查找会更加困难和昂贵。
编辑,修改代码。性能实际上更差:(
根据建议,我将 5000 人的 list 分成了多个部分。我玩了几个不同的尺寸。 300 和 500,两者保存数据的时间非常相似。这是现在的样子:
saveLocations(db, stores) { // position
var storeSlices = [];
stores.sort(function (a, b) {
return a.id - b.id;
});
stores.eachSlice(300, (slice) => {
storeSlices.push(slice);
});
console.log(Date.now());
this.commitBatch(db, storeSlices, 0, () => {
console.log(Date.now());
// this.sortAndRenderStores(docs, position);
this.render("store-list", { stores: [] });
});
}
commitBatch(db, slices, index, callback) {
let stores = slices[index];
db.allDocs({ include_docs: true, startkey: 'store_' + stores[0].id, endkey: 'store_' + stores[stores.length - 1].id }).then((results) => {
let docs = [];
for (let row of results.rows) {
let doc = row.doc;
let id = parseFloat(doc._id.split('store_')[1]);
if (isNaN(id)) {
throw "Cannot be NaN";
}
// iterate through stores from api
for (var i = 0; i < stores.length; i++) {
let store = stores[i];
// find store and local record
if (store.id === id) {
let map = PouchProxy.storeToDocMap(store);
// set revision
map._rev = doc._rev;
docs.push(map);
stores.splice(i, 1);
break;
}
}
}
// go through remaining stores and push to docs set
for (let store of stores) {
docs.push(PouchProxy.storeToDocMap(store));
}
db.bulkDocs(docs).then(() => {
index++;
if (index < slices.length) {
this.commitBatch(db, slices, index, callback);
}
else {
callback();
}
});
}).catch(function (err) {
console.log(err);
});
}
最佳答案
我的猜测是,这里的问题是您正在一次性将所有文档读入内存(或者至少,每个文档都以 store_
为前缀,这就是您的 allDocs()
正在做),然后您也将一次性编写所有这些文档。
5000 份文件很多。我对 PouchDB 的经验是,bulkDocs()
有一个最佳点(取决于您的文档大小),它可能远小于 5000。这适用于 IndexedDB 和 WebSQL。
很可能您可以通过批处理 100-500 block 来加速您的代码,同时使用 limit
和 startkey
在 allDocs()
中分页>(即使用 this blog post 中描述的策略),然后使用 bulkDocs()
一次插入 100-500。
为了证明我没有撒谎,你可以查看http://npm-browser.com/ ,它在单个 bulkDocs()
中每批插入大约 500 个来自 npm 的元数据文档,并且绝对不会每批花费 7 秒。 (大部分时间花在等待网络下载文件上。)
关于javascript - PouchDB 通过 websql 插入 4800 个文档慢了大约 3 倍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30536760/