戻る

order by 複数フィールド
indexedDB

IndexedDB は1回のカーソル操作で使えるのは1つのインデックス(またはオブジェクトストア)です。
2つのインデックスを並列に回して「ORDER BY f1, f2」のようなことはできません。
実現する方法としては
「複合インデックス」を実装するか
「メモリでソート」を実装するか
のどちらかとなります。
このサンプルでは、メモリでソートをすると大きいデータの場合メモリ負荷が増え、圧迫されてしまうことから
複合インデックスを準備してソートをする方法となります。

[サンプル]
copy
async function testOrderByPluralIndex(dbName, storeName, sortType) 
{
	const db = await databaseOpen(dbName);
	
	const rows = await runTx(db, storeName, "readonly", (store) => 
	{
		return new Promise((resolve, reject) => {
		const index = store.index("f1_f2");
		const direction = sortType === 0 ? "next" : "prev";
		const result = [];
	
		const req = index.openCursor(null, direction);
		req.onsuccess = (event) => {
			const cursor = event.target.result;
			if (cursor) {
				console.log(cursor.value);
				result.push(cursor.value);
				cursor.continue();
			} 
			else 
			{
				//cursor end
				resolve(result);
			}
		};
		req.onerror = () => reject(req.error);
		});
	});
	
	db.close();
	return rows;
}
function databaseOpen(dbName) 
{
	return new Promise((resolve, reject) => 
	{
		const req = indexedDB.open(dbName);
		req.onsuccess = (event) => 
		{
			resolve(event.target.result);
		};
		req.onerror = () => reject(req.error);
	});
}
function waitForTx(tx) 
{
	return new Promise((resolve, reject) => 
	{
		tx.oncomplete = () => resolve();
		tx.onabort = () => reject(tx.error ?? new Error("Transaction aborted"));
		tx.onerror = () => reject(tx.error);
	});
}

async function runTx(db, storeName, mode, work) 
{
	const tx = db.transaction([storeName], mode);
	const store = tx.objectStore(storeName);
	const result = await work(store);
	await waitForTx(tx);
	return result;
}
//asc
testOrderByPluralIndex("sampleDB", "t2", 0)
.then(rowsAsc => {
	console.log("asc result:", rowsAsc);
})
.catch(error => {
	console.error("asc error:", error);
});

//desc
testOrderByPluralIndex("sampleDB", "t2", 1)
.then(rowsDesc => {
	console.log("desc result:", rowsDesc);
})
.catch(error => {
	console.error("desc error:", error);
});

このサンプルでは下記のようにオブジェクトスキーマを実装しています。
const store = db.createObjectStore("t2", { keyPath: "f0" });
store.createIndex("f1", "f1", { unique: false });
store.createIndex("f2", "f2", { unique: false });
store.createIndex("f3", "f3", { unique: false });
store.createIndex("f4", "f4", { unique: false });
//追加:f1 → f2 の並び
store.createIndex("f1_f2", ["f1", "f2"]);

const rows = await runTx(db, storeName, "readonly", (store) =>
indexedDBのカーソル処理は非同期のため、Promise化して待つ必要があります。
runTxの引数work関数からawait work(store)を実行すると
await runTxの内部で実装したカーソルの実行処理が
コミット完了するまで待ち状態となります。

await waitForTx(tx);
トランザクションがコミットもしくはアボートされるまで待機します。
こうして得たカーソルの情報が配列としてrows配列に返されます。

const index = objectStore.index("f1_f2");
「f1_f2」は事前に作成しておきます。

store.createIndex("f1_f2", ["f1", "f2"]);
複合インデックスを使って f1 → f2 で並べ替えを準備します。

const cursor = event.target.result;
カーソルを準備します。

console.log(cursor.value);
カーソルのデータを出力します。

cursor.continue();
次のカーソルをコールします。




戻る


著作権情報
ホームページおよプリ等に掲載されている情報等については、いかなる保障もいたしません。
ホームページおよびアプリ等を通じて入手したいかなる情報も複製、販売、出版または使用させたり、
または公開したりすることはできません。
当方は、ホームペーよびアプリ利用したいかなる理由によっての障害等が発生しても、
その結果ホームページおよびアプリ等を利用された本人または他の第三者が被った損害について
一切の責任を負わないものとします。