OR or IN operation in IndexedDB

前端 未结 4 874
一整个雨季
一整个雨季 2020-12-19 14:19

Is there a way to do an OR or IN query on the same property in IndexedDB?

Another word, how do I get the results for,

SELECT * FROM MyTable WHERE col         


        
相关标签:
4条回答
  • 2020-12-19 14:48

    This is a simple query equivalent to your sql query using JsStore Library

    var Connection = new JsStore.Instance("MyDatabase");
    Connection.select({
        From: "MyTable",
        Where:{
            columnA : {In:['ABC','DFT')]},
            columnB : '123thd'
        },
        OnSuccess:function (results){
            console.log(results);
        },
        OnError:function (error) {
            console.log(error);
        }
    });
    

    Hope this will save your time and code:).

    0 讨论(0)
  • 2020-12-19 14:54

    This functionality isn't present in the indexedDB API. You are only allowed to filter on a single index. You can try one of the libraries that are written around the indexedDB API. Some of them provide extra filter functionality.

    • linq2indexeddb
    • ydn
    • dash
    0 讨论(0)
  • 2020-12-19 15:02

    There's no way to do a OR or IN-like query out of the box without during multiple requests. Usually the pattern for problems like this is "over reach, pulling more entries then you need and filtering those down to exact matches."

    The Chrome team has proposed a openKeyCursor() method as a solution for this kind of query (thanks to the suggestion of Kyaw Tun, a fellow SO participant and author of ydn), but it's not standard nor adopted in other browsers.

    The best solution I can think of is similar to Comment #4 of the w3 thread:

    • Open exact key cursor on columnB using value '123thd'
    • Cursor across all those records, matching objects for columnA values 'ABC' and 'DFT'

    If generally you expect the number of results where columnB is '123thd' to be quite large, and most don't have values 'ABC' or 'DFT', then it may behoove you to open two cursors instead - one on columnA w/value 'ABC' and another with value 'DFT'. It's a more complex approach because you'll have to merge the two results sets manually.

    0 讨论(0)
  • 2020-12-19 15:04

    Solution with 2 successive queries using a compound index:

    1. Create a compound index on columnA and columnB. See this post for an example.
    2. Query with range parameter ['ABC','123thd'] and iterate over its results.
    3. Query with range parameter ['DFT','123thd'] and iterate over its results.

    Solution with 1 query using a derived property:

    The drawback of this approach is you need to know the queries you plan to execute and have to adapt this method for each query. This is something you should be doing even with SQL. Unfortunately, because many developers do not bother with proper query planning, this is not so obvious, so it is like an additional requirement to learn and start using before using indexedDB. However, proper query planning does yield better performance.

    // In onupgradeneeded
    function myOnUpgradeNeeded(event) {
      var db = event.target.result;
      var store = db.createObjectStore('MyTable');
    
      // Create a compound index on the derived property of columnA
      // and the normal property of columnB
      store.createIndex('A_ABC_OR_DFT_AND_B', ['ABC_OR_DFT_FLAG','columnB']);
    }
    
    
    function wrappedPut(db, obj, callback) {
      // Set the flag property
      // indexedDB cannot index booleans, so we use simple integer representation
      // where 1 represents true, 0 represents false. But we can go further since
      // we know that undefined properties dont appear in the index.
    
     if(obj.columnA=='ABC'||obj.columnA=='DFT') {
       obj.ABC_OR_DFT_FLAG = 1;
     } else {
       delete obj.ABC_OR_DFT_FLAG;
     }
    
     put(db, obj, callback);
    }
    
    // In your add/update function
    function put(db, obj, callback) {
     db.transaction('MyTable','readwrite').objectStore('myTable').put(obj).onsuccess = callback;
    }
    
    // Voila, a single efficient high speed query over all items 
    // in MyTable where columnA is ABC or DFT and where columnB 
    // is 123thd, using a single index, without using a 3rd party
    // library, and without doing some horrible double cursor stuff
    // in javascript, and just using the indexedDB API.
    function runTheABCDFT123Query(db, onSuccess, onComplete) {
      var tx = db.transaction('MyTable');
      tx.onComplete = onComplete;
      tx.objectStore('MyTable').index('A_ABC_OR_DFT_AND_B').openCursor(
        IDBKeyRange.only([1,'123thd'])).onsuccess = function(event) {
        if(event.target) {
          onSuccess(event.target.value);
          event.target.continue();
        }
      };
    }
    
    0 讨论(0)
提交回复
热议问题