IndexedDB est une architecture similaire à une base de données SQL, car elle contient des tables, des lignes et des transactions, même si elles sont nommées différemment (Table = ObjectStore, row = Object).
En utilisant Dexie, il est assez facile de faire ce genre de jointures typiques avec des clés étrangères. IndexedDB ne vérifie pas les contraintes des clés étrangères, mais vous pouvez effectuer des requêtes similaires aux jointures SQL.
Il existe un addon à dexie, dexie-relationships, qui peut aider à effectuer les requêtes de jointure.
import Dexie from 'dexie'
import relationships from 'dexie-relationships'
class OrdersDB extends Dexie {
customers: Dexie.Table<Customer, string>;
products: Dexie.Table<Producs, string>;
pricesPerCustomer: Dexie.Table<PricePerCustomer, string>;
orders: Dexie.Table<Order, string>;
constructor() {
super ("OrdersDB", {addons: [relationships]});
this.version(1).stores({
customers: 'id, name',
products: 'id, name',
pricesPerCustomer: `
id,
customerId -> customers.id,
productId -> products.id,
[customerId+productId]`, // Optimizes compound query (see below)
orders: `
id,
customerId -> customers.id,
productId -> products.id`
});
}
}
interface Customer {
id: string;
name: string;
orders?: Order[]; // db.customers.with({orders: 'orders'})
prices?: PricesPerCustomer[]; // with({prices: 'pricesPerCustomer'})
}
interface Product {
id: string;
name: string;
prices?: PricesPerCustomer[]; // with({prices: 'pricesPerCustomer'})
}
interface PricePerCustomer {
id: string;
price: number;
currency: string;
customerId: string;
customer?: Customer; // with({customer: 'customerId'})
productId: string;
product?: Product; // with({product: 'productId'})
}
interface Order {
id: string;
customerId: string;
customer?: Customer; // with({customer: 'customerId'})
productId: string;
product?: Product; // with({product: 'productId'})
quantity: number;
price?: number; // When returned from getOrders() below.
currency?: string; // --"--
}
const db = new OrdersDB();
/* Returns array of Customer with the "orders" and "prices" arrays attached.
*/
async function getCustomersBeginningWithA() {
return await db.customers.where('name').startsWithIgnoreCase('a')
.with({orders: 'orders', prices: 'pricesPerCustomer'});
}
/* Returns the price for a certain customer and product using
a compound query (Must use Dexie 2.0 for this). The query is
optimized if having a compound index ['customerId+productId']
declared in the database schema (as done above).
*/
async function getPrice (customerId: string, productId: string) {
return await db.pricesPerCustomer.get({
customerId: customerId,
productId: productId
});
}
async function getOrders (customerId: string) {
// Load orders for given customer with product property set.
const orders = await db.orders.where({customerId: customerId})
.with({product: 'productId'});
// Load prices for this each customer/product
const prices = await Promise.all(orders.map(order =>
getPrice(customerId, order.id)));
// Return orders with price and currency properties set:
return orders.map((order, idx) => {
const pricePerCustomer = prices[idx];
return {
...order,
price: pricePerCustomer.price,
currency: pricePerCustomer.currency
};
});
}
Notez que j'ai déclaré chaque clé primaire comme une chaîne, de sorte que vous devrez inventer chaque clé manuellement. Pourrait avoir utilisé des nombres générés automatiquement aussi (en utilisant "++ id, ..." au lieu de "id, ...") dans la déclaration de schéma. Si oui, déclarez les tables comme Dexie.Table < Client, numéro > au lieu de Dexie.Table < Client, chaîne >.
Merci David, et est-ce qu'il fonctionne bien si par exemple je dois joindre une table de 1000 enregistrements et une deuxième table avec plus de 200.000 enregistrements? – DarioN1
Chaque requête de l'exemple utilise les index de la manière la plus optimale. Il n'y a pas d'analyse de table complète ou autre. Pour obtenir la performance exacte, vous devrez le mesurer bien. –
Si vous obtenez des chiffres de performance, pleace nous le faire savoir. Aussi si vous trouvez des problèmes avec l'échantillon (comme il n'est pas compilé/testé) –