Using IndexedDB as an in-browser cache. Am I doing it right? Announcing the arrival of Valued...

What LEGO pieces have "real-world" functionality?

Book where humans were engineered with genes from animal species to survive hostile planets

What is a non-alternating simple group with big order, but relatively few conjugacy classes?

Output the ŋarâþ crîþ alphabet song without using (m)any letters

How to find all the available tools in macOS terminal?

Should I discuss the type of campaign with my players?

Withdrew £2800, but only £2000 shows as withdrawn on online banking; what are my obligations?

Sci-Fi book where patients in a coma ward all live in a subconscious world linked together

How to bypass password on Windows XP account?

Dating a Former Employee

Why is my conclusion inconsistent with the van't Hoff equation?

porting install scripts : can rpm replace apt?

The logistics of corpse disposal

Are two submodules (where one is contained in the other) isomorphic if their quotientmodules are isomorphic?

Align equal signs while including text over equalities

What's the meaning of 間時肆拾貳 at a car parking sign

ListPlot join points by nearest neighbor rather than order

Selecting the same column from Different rows Based on Different Criteria

What's the purpose of writing one's academic biography in the third person?

At the end of Thor: Ragnarok why don't the Asgardians turn and head for the Bifrost as per their original plan?

What does this icon in iOS Stardew Valley mean?

Is there a (better) way to access $wpdb results?

Using et al. for a last / senior author rather than for a first author

How to run gsettings for another user Ubuntu 18.04.2 LTS



Using IndexedDB as an in-browser cache. Am I doing it right?



Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)Conversion of datetime strings in PHP pages to user's timezoneSend parameter to server and reload pageJavaScript Weather AppRecognizing elements and doing event handling for repeating templatesCross-browser UI-less replacement of console.logReading content of directory for each HTTP requestUsing promises to GET and process dataJSON data serializationFetching and parsing JSON data from the Oodle APIIOT Javascript GUI/Hub - Displaying Incoming Data





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}







0












$begingroup$


In my site:




  • Users have many Activities

  • Each Activity has encoded_polyline data

  • I display these encoded_polylines on a map


I want to use IndexedDB (via Dexie) as an in-browser cache so that they don't need to re-download their full Activity set every time they view their map. I've never used IndexedDB before, so I don't know if I'm doing anything silly or overlooking any edge cases.





Here's a high-level description of what I think the overall process is:




  • Figure out what exists on the server

  • Remove anything that is present in IndexedDB but is not present on the server

  • Figure out what exists in IndexedDB

  • Request only the data missing in IndexedDB

  • Store the new data in IndexedDB

  • Query all of the data out of IndexedDB


Throughout all of this, we need to be focusing on this user. A person might view many people's pages, and therefore have a copy of many people's data in IndexedDB. So the queries to the server and IndexedDB need to be aware of which User ID is being referenced.





Here's the English Language version of what I decided to do:




  • Collect all of this User's Activty IDs from the server

  • Remove anything in IndexedDB that shouldn't be there (stuff deleted from the site that might still exist in IndexedDB)

  • Collect all of this User's Activty IDs from IndexedDB

  • Filter out anything that's present in IndexedDB and the server

  • If there are no new encoded_polylines to retrieve then putItemsFromIndexeddbOnMap (described below)

  • If there are new encoded_polylines to retrieve: retrieve those from the server, then store them in IndexedDB, then putItemsFromIndexeddbOnMap


For putItemsFromIndexeddbOnMap:




  • Get all of this user's encoded_polylines from IndexedDB

  • Push that data into an array

  • Display that array of data on the map




Here's the JavaScript code that does what I've explained above (with some ERB because this JavaScript is embedded in a Rails view):



var db = new Dexie("db_name");
db.version(1).stores({ activities: "id,user_id" });
db.open();

// get this user's activity IDs from the server
fetch('/users/' + <%= @user.id %> + '/activity_ids.json', { credentials: 'same-origin' }
).then(response => { return response.json() }
).then(activityIdsJson => {
// remove items from IndexedDB for this user that are not in activityIdsJson
// this keeps data that was deleted in the site from sticking around in IndexedDB
db.activities
.where('id')
.noneOf(activityIdsJson)
.and(function(item) { return item.user_id === <%= @user.id %> })
.keys()
.then(removeActivityIds => {
db.activities.bulkDelete(removeActivityIds);
});

// get this user's existing activity IDs out of IndexedDB
db.activities.where({user_id: <%= @user.id %>}).primaryKeys(function(primaryKeys) {
// filter out the activity IDs that are already in IndexedDB
var neededIds = activityIdsJson.filter((id) => !primaryKeys.includes(id));

if(Array.isArray(neededIds) && neededIds.length === 0) {
// we do not need to request any new data so query IndexedDB directly
putItemsFromIndexeddbOnMap();
} else if(Array.isArray(neededIds)) {
if(neededIds.equals(activityIdsJson)) {
// we need all data so do not pass the `only` param
neededIds = [];
}

// get new data (encoded_polylines for display on the map)
fetch('/users/' + <%= @user.id %> + '/encoded_polylines.json?only=' + neededIds, { credentials: 'same-origin' }
).then(response => { return response.json() }
).then(newEncodedPolylinesJson => {
// store the new encoded_polylines in IndexedDB
db.activities.bulkPut(newEncodedPolylinesJson).then(_unused => {
// pull all encoded_polylines out of IndexedDB
putItemsFromIndexeddbOnMap();
});
});
}
});
});

function putItemsFromIndexeddbOnMap() {
var featureCollection = [];

db.activities.where({user_id: <%= @user.id %>}).each(activity => {
featureCollection.push({
type: 'Feature',
geometry: polyline.toGeoJSON(activity['encoded_polyline'])
});
}).then(function() {
// if there are any polylines, add them to the map
if(featureCollection.length > 0) {
if(map.isStyleLoaded()) {
// map has fully loaded so add polylines to the map
addPolylineLayer(featureCollection);
} else {
// map is still loading, so wait for that to complete
map.on('style.load', addPolylineLayer(featureCollection));
}
}
}).catch(error => {
console.error(error.stack || error);
});
}

function addPolylineLayer(data) {
map.addSource('polylineCollection', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: data
}
});
map.addLayer({
id: 'polylineCollection',
type: 'line',
source: 'polylineCollection'
});
}


...Am I doing it right?









share









$endgroup$



















    0












    $begingroup$


    In my site:




    • Users have many Activities

    • Each Activity has encoded_polyline data

    • I display these encoded_polylines on a map


    I want to use IndexedDB (via Dexie) as an in-browser cache so that they don't need to re-download their full Activity set every time they view their map. I've never used IndexedDB before, so I don't know if I'm doing anything silly or overlooking any edge cases.





    Here's a high-level description of what I think the overall process is:




    • Figure out what exists on the server

    • Remove anything that is present in IndexedDB but is not present on the server

    • Figure out what exists in IndexedDB

    • Request only the data missing in IndexedDB

    • Store the new data in IndexedDB

    • Query all of the data out of IndexedDB


    Throughout all of this, we need to be focusing on this user. A person might view many people's pages, and therefore have a copy of many people's data in IndexedDB. So the queries to the server and IndexedDB need to be aware of which User ID is being referenced.





    Here's the English Language version of what I decided to do:




    • Collect all of this User's Activty IDs from the server

    • Remove anything in IndexedDB that shouldn't be there (stuff deleted from the site that might still exist in IndexedDB)

    • Collect all of this User's Activty IDs from IndexedDB

    • Filter out anything that's present in IndexedDB and the server

    • If there are no new encoded_polylines to retrieve then putItemsFromIndexeddbOnMap (described below)

    • If there are new encoded_polylines to retrieve: retrieve those from the server, then store them in IndexedDB, then putItemsFromIndexeddbOnMap


    For putItemsFromIndexeddbOnMap:




    • Get all of this user's encoded_polylines from IndexedDB

    • Push that data into an array

    • Display that array of data on the map




    Here's the JavaScript code that does what I've explained above (with some ERB because this JavaScript is embedded in a Rails view):



    var db = new Dexie("db_name");
    db.version(1).stores({ activities: "id,user_id" });
    db.open();

    // get this user's activity IDs from the server
    fetch('/users/' + <%= @user.id %> + '/activity_ids.json', { credentials: 'same-origin' }
    ).then(response => { return response.json() }
    ).then(activityIdsJson => {
    // remove items from IndexedDB for this user that are not in activityIdsJson
    // this keeps data that was deleted in the site from sticking around in IndexedDB
    db.activities
    .where('id')
    .noneOf(activityIdsJson)
    .and(function(item) { return item.user_id === <%= @user.id %> })
    .keys()
    .then(removeActivityIds => {
    db.activities.bulkDelete(removeActivityIds);
    });

    // get this user's existing activity IDs out of IndexedDB
    db.activities.where({user_id: <%= @user.id %>}).primaryKeys(function(primaryKeys) {
    // filter out the activity IDs that are already in IndexedDB
    var neededIds = activityIdsJson.filter((id) => !primaryKeys.includes(id));

    if(Array.isArray(neededIds) && neededIds.length === 0) {
    // we do not need to request any new data so query IndexedDB directly
    putItemsFromIndexeddbOnMap();
    } else if(Array.isArray(neededIds)) {
    if(neededIds.equals(activityIdsJson)) {
    // we need all data so do not pass the `only` param
    neededIds = [];
    }

    // get new data (encoded_polylines for display on the map)
    fetch('/users/' + <%= @user.id %> + '/encoded_polylines.json?only=' + neededIds, { credentials: 'same-origin' }
    ).then(response => { return response.json() }
    ).then(newEncodedPolylinesJson => {
    // store the new encoded_polylines in IndexedDB
    db.activities.bulkPut(newEncodedPolylinesJson).then(_unused => {
    // pull all encoded_polylines out of IndexedDB
    putItemsFromIndexeddbOnMap();
    });
    });
    }
    });
    });

    function putItemsFromIndexeddbOnMap() {
    var featureCollection = [];

    db.activities.where({user_id: <%= @user.id %>}).each(activity => {
    featureCollection.push({
    type: 'Feature',
    geometry: polyline.toGeoJSON(activity['encoded_polyline'])
    });
    }).then(function() {
    // if there are any polylines, add them to the map
    if(featureCollection.length > 0) {
    if(map.isStyleLoaded()) {
    // map has fully loaded so add polylines to the map
    addPolylineLayer(featureCollection);
    } else {
    // map is still loading, so wait for that to complete
    map.on('style.load', addPolylineLayer(featureCollection));
    }
    }
    }).catch(error => {
    console.error(error.stack || error);
    });
    }

    function addPolylineLayer(data) {
    map.addSource('polylineCollection', {
    type: 'geojson',
    data: {
    type: 'FeatureCollection',
    features: data
    }
    });
    map.addLayer({
    id: 'polylineCollection',
    type: 'line',
    source: 'polylineCollection'
    });
    }


    ...Am I doing it right?









    share









    $endgroup$















      0












      0








      0





      $begingroup$


      In my site:




      • Users have many Activities

      • Each Activity has encoded_polyline data

      • I display these encoded_polylines on a map


      I want to use IndexedDB (via Dexie) as an in-browser cache so that they don't need to re-download their full Activity set every time they view their map. I've never used IndexedDB before, so I don't know if I'm doing anything silly or overlooking any edge cases.





      Here's a high-level description of what I think the overall process is:




      • Figure out what exists on the server

      • Remove anything that is present in IndexedDB but is not present on the server

      • Figure out what exists in IndexedDB

      • Request only the data missing in IndexedDB

      • Store the new data in IndexedDB

      • Query all of the data out of IndexedDB


      Throughout all of this, we need to be focusing on this user. A person might view many people's pages, and therefore have a copy of many people's data in IndexedDB. So the queries to the server and IndexedDB need to be aware of which User ID is being referenced.





      Here's the English Language version of what I decided to do:




      • Collect all of this User's Activty IDs from the server

      • Remove anything in IndexedDB that shouldn't be there (stuff deleted from the site that might still exist in IndexedDB)

      • Collect all of this User's Activty IDs from IndexedDB

      • Filter out anything that's present in IndexedDB and the server

      • If there are no new encoded_polylines to retrieve then putItemsFromIndexeddbOnMap (described below)

      • If there are new encoded_polylines to retrieve: retrieve those from the server, then store them in IndexedDB, then putItemsFromIndexeddbOnMap


      For putItemsFromIndexeddbOnMap:




      • Get all of this user's encoded_polylines from IndexedDB

      • Push that data into an array

      • Display that array of data on the map




      Here's the JavaScript code that does what I've explained above (with some ERB because this JavaScript is embedded in a Rails view):



      var db = new Dexie("db_name");
      db.version(1).stores({ activities: "id,user_id" });
      db.open();

      // get this user's activity IDs from the server
      fetch('/users/' + <%= @user.id %> + '/activity_ids.json', { credentials: 'same-origin' }
      ).then(response => { return response.json() }
      ).then(activityIdsJson => {
      // remove items from IndexedDB for this user that are not in activityIdsJson
      // this keeps data that was deleted in the site from sticking around in IndexedDB
      db.activities
      .where('id')
      .noneOf(activityIdsJson)
      .and(function(item) { return item.user_id === <%= @user.id %> })
      .keys()
      .then(removeActivityIds => {
      db.activities.bulkDelete(removeActivityIds);
      });

      // get this user's existing activity IDs out of IndexedDB
      db.activities.where({user_id: <%= @user.id %>}).primaryKeys(function(primaryKeys) {
      // filter out the activity IDs that are already in IndexedDB
      var neededIds = activityIdsJson.filter((id) => !primaryKeys.includes(id));

      if(Array.isArray(neededIds) && neededIds.length === 0) {
      // we do not need to request any new data so query IndexedDB directly
      putItemsFromIndexeddbOnMap();
      } else if(Array.isArray(neededIds)) {
      if(neededIds.equals(activityIdsJson)) {
      // we need all data so do not pass the `only` param
      neededIds = [];
      }

      // get new data (encoded_polylines for display on the map)
      fetch('/users/' + <%= @user.id %> + '/encoded_polylines.json?only=' + neededIds, { credentials: 'same-origin' }
      ).then(response => { return response.json() }
      ).then(newEncodedPolylinesJson => {
      // store the new encoded_polylines in IndexedDB
      db.activities.bulkPut(newEncodedPolylinesJson).then(_unused => {
      // pull all encoded_polylines out of IndexedDB
      putItemsFromIndexeddbOnMap();
      });
      });
      }
      });
      });

      function putItemsFromIndexeddbOnMap() {
      var featureCollection = [];

      db.activities.where({user_id: <%= @user.id %>}).each(activity => {
      featureCollection.push({
      type: 'Feature',
      geometry: polyline.toGeoJSON(activity['encoded_polyline'])
      });
      }).then(function() {
      // if there are any polylines, add them to the map
      if(featureCollection.length > 0) {
      if(map.isStyleLoaded()) {
      // map has fully loaded so add polylines to the map
      addPolylineLayer(featureCollection);
      } else {
      // map is still loading, so wait for that to complete
      map.on('style.load', addPolylineLayer(featureCollection));
      }
      }
      }).catch(error => {
      console.error(error.stack || error);
      });
      }

      function addPolylineLayer(data) {
      map.addSource('polylineCollection', {
      type: 'geojson',
      data: {
      type: 'FeatureCollection',
      features: data
      }
      });
      map.addLayer({
      id: 'polylineCollection',
      type: 'line',
      source: 'polylineCollection'
      });
      }


      ...Am I doing it right?









      share









      $endgroup$




      In my site:




      • Users have many Activities

      • Each Activity has encoded_polyline data

      • I display these encoded_polylines on a map


      I want to use IndexedDB (via Dexie) as an in-browser cache so that they don't need to re-download their full Activity set every time they view their map. I've never used IndexedDB before, so I don't know if I'm doing anything silly or overlooking any edge cases.





      Here's a high-level description of what I think the overall process is:




      • Figure out what exists on the server

      • Remove anything that is present in IndexedDB but is not present on the server

      • Figure out what exists in IndexedDB

      • Request only the data missing in IndexedDB

      • Store the new data in IndexedDB

      • Query all of the data out of IndexedDB


      Throughout all of this, we need to be focusing on this user. A person might view many people's pages, and therefore have a copy of many people's data in IndexedDB. So the queries to the server and IndexedDB need to be aware of which User ID is being referenced.





      Here's the English Language version of what I decided to do:




      • Collect all of this User's Activty IDs from the server

      • Remove anything in IndexedDB that shouldn't be there (stuff deleted from the site that might still exist in IndexedDB)

      • Collect all of this User's Activty IDs from IndexedDB

      • Filter out anything that's present in IndexedDB and the server

      • If there are no new encoded_polylines to retrieve then putItemsFromIndexeddbOnMap (described below)

      • If there are new encoded_polylines to retrieve: retrieve those from the server, then store them in IndexedDB, then putItemsFromIndexeddbOnMap


      For putItemsFromIndexeddbOnMap:




      • Get all of this user's encoded_polylines from IndexedDB

      • Push that data into an array

      • Display that array of data on the map




      Here's the JavaScript code that does what I've explained above (with some ERB because this JavaScript is embedded in a Rails view):



      var db = new Dexie("db_name");
      db.version(1).stores({ activities: "id,user_id" });
      db.open();

      // get this user's activity IDs from the server
      fetch('/users/' + <%= @user.id %> + '/activity_ids.json', { credentials: 'same-origin' }
      ).then(response => { return response.json() }
      ).then(activityIdsJson => {
      // remove items from IndexedDB for this user that are not in activityIdsJson
      // this keeps data that was deleted in the site from sticking around in IndexedDB
      db.activities
      .where('id')
      .noneOf(activityIdsJson)
      .and(function(item) { return item.user_id === <%= @user.id %> })
      .keys()
      .then(removeActivityIds => {
      db.activities.bulkDelete(removeActivityIds);
      });

      // get this user's existing activity IDs out of IndexedDB
      db.activities.where({user_id: <%= @user.id %>}).primaryKeys(function(primaryKeys) {
      // filter out the activity IDs that are already in IndexedDB
      var neededIds = activityIdsJson.filter((id) => !primaryKeys.includes(id));

      if(Array.isArray(neededIds) && neededIds.length === 0) {
      // we do not need to request any new data so query IndexedDB directly
      putItemsFromIndexeddbOnMap();
      } else if(Array.isArray(neededIds)) {
      if(neededIds.equals(activityIdsJson)) {
      // we need all data so do not pass the `only` param
      neededIds = [];
      }

      // get new data (encoded_polylines for display on the map)
      fetch('/users/' + <%= @user.id %> + '/encoded_polylines.json?only=' + neededIds, { credentials: 'same-origin' }
      ).then(response => { return response.json() }
      ).then(newEncodedPolylinesJson => {
      // store the new encoded_polylines in IndexedDB
      db.activities.bulkPut(newEncodedPolylinesJson).then(_unused => {
      // pull all encoded_polylines out of IndexedDB
      putItemsFromIndexeddbOnMap();
      });
      });
      }
      });
      });

      function putItemsFromIndexeddbOnMap() {
      var featureCollection = [];

      db.activities.where({user_id: <%= @user.id %>}).each(activity => {
      featureCollection.push({
      type: 'Feature',
      geometry: polyline.toGeoJSON(activity['encoded_polyline'])
      });
      }).then(function() {
      // if there are any polylines, add them to the map
      if(featureCollection.length > 0) {
      if(map.isStyleLoaded()) {
      // map has fully loaded so add polylines to the map
      addPolylineLayer(featureCollection);
      } else {
      // map is still loading, so wait for that to complete
      map.on('style.load', addPolylineLayer(featureCollection));
      }
      }
      }).catch(error => {
      console.error(error.stack || error);
      });
      }

      function addPolylineLayer(data) {
      map.addSource('polylineCollection', {
      type: 'geojson',
      data: {
      type: 'FeatureCollection',
      features: data
      }
      });
      map.addLayer({
      id: 'polylineCollection',
      type: 'line',
      source: 'polylineCollection'
      });
      }


      ...Am I doing it right?







      javascript





      share












      share










      share



      share










      asked 4 mins ago









      James ChevalierJames Chevalier

      1286




      1286






















          0






          active

          oldest

          votes












          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f217586%2fusing-indexeddb-as-an-in-browser-cache-am-i-doing-it-right%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f217586%2fusing-indexeddb-as-an-in-browser-cache-am-i-doing-it-right%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Webac Holding Inhaltsverzeichnis Geschichte | Organisationsstruktur | Tochterfirmen |...

          What's the meaning of a knight fighting a snail in medieval book illustrations?What is the meaning of a glove...

          Salamanca Inhaltsverzeichnis Lage und Klima | Bevölkerungsentwicklung | Geschichte | Kultur und...