2017-10-13 6 views
0

Je dois réaliser une application Web qui utilise LocalDB pour gérer la création de commandes hors ligne.IndexedDB - Manière correcte de stocker une grande quantité de données

En ce moment j'implémente le LocalDB en utilisant Dexie pour Angular2/Typescript.

Ce que je dois faire est de réaliser une base de données afin de pouvoir gérer:

  • clients (+1000 enregistrements)
  • Produits (+2000) dossiers
  • Produits
  • Prix défini par clients + (100.000 enregistrements)
  • Commandes (peu de données)

etc ...

Il doit gérer lof de données, parce que les produits, les clients et les prix sont beaucoup ou dossiers ...

Ma question est la suivante:

Si je dois réalisé cette base de données en utilisant une base de données relationnelle commune comme SQL Server ou MySql, lorsque je compose l'ordre temporaire, je stocke l'idMaterial et les quantités ...

Mais ce que je dois faire dans IndexedDB?

Il est préférable de stocker l'ordre temporaire comme pour MySql/SqlServer en utilisant idMaterial/Quantité et retrive les informations du produit (si nécessaire) en faisant INNER JOIN ou son mieux à stocker dans une table locale toutes les informations des produits/Prix ​​ afin d'éviter les requêtes INNER JOIN? Puis-je lancer INNER JOIN entre des tables réunissant plus de 2 000 produits et 100 000 produits? Prix défini par client?

Grâce à l'appui!

Répondre

1

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 >.

+0

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

+1

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. –

+1

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é) –