arrow-left

All pages
gitbookPowered by GitBook
1 of 8

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Basic Data Use

Now that we have a functional Enmap structure (which we'll always refer to as myEnmap), we're ready to start writing data to it, and getting data from it.

The code samples on this page assume that you have correctly initialized myEnmap, and awaited its initialization if it's persistent.

hashtag
Writing Data

In terms of Enmap, "writing", "adding" and "editing" data is essentially the same thing. When using the basic set() method, if the key does not exist it's created, and if it does, it's modified.

Enmap supports most native JavaScript data types, with a few small exceptions.

  • Complex objects like Set(), Map(), etc, are not supported.

  • Class instances and Functions are not supported.

As a general rule, except for null and undefined, anything that can be handled by JSON.stringify() will work as expected in Enmap. This includes:

  • String

  • Number

  • Integer

Objects and Arrays are a little more complex to deal with, so they have their own page. See for more information.

The usage for the set() method is simple:

  • key must be a string or integer. A key should be unique, otherwise it will be overwritten by new values using the same key.

  • value must be a supported native data type as mentioned above.

Here are a few examples of writing simple data values:

hashtag
Retrieving Data

Getting data back from an Enmap is just as simple as writing to it. All you need is the key of what you want to retrieve, and you get its value back!

That's pretty much it for only retrieiving a single data value. There are more complex operations that are available, take a look at for the more advanced things you can do on Enmap's data!

Boolean
  • Object

  • Array

  • Working with Objects
    Array Methods
    <Enmap>.set(key, value);
    myEnmap.set('boolean', true);
    myEnmap.set('integer', 42);
    myEnmap.set('someFloat', 73.2345871);
    myEnmap.set("Test2", "test2");
    const floatValue = myEnmap.get('someFloat');
    const test = myEnmap.get('Test2');
    
    // you can even use booleans in conditions: 
    if(myEnmap.get('boolean')) {
      // boolean is true!
    }

    Persistent Enmaps

    Persistence requires an additional Provider module.

    Official Enmap Providers:

    • Enmap-SQLitearrow-up-right: Recommended, supports sharding locally.

    • Enmap-Rethinkarrow-up-right: Best for sharding if you can install a rethinkdb server. Supports updating from the database on all shards (enmap-rethink 2.1.0 and higher)

    • : Postgresql database provider. Supports Sharding.

    • : Mongodb database provider. Supports Sharding.

    • Sort of not recommended at this point, doesn't support sharding, no longer the most efficient/faster provider.

    When using any provider, it's very important to understand that it takes time to load the data from the database. Certain providers also take some time to even open the database connection, and that's also something to consider.

    hashtag
    Using defer

    To make sure that all your data is loaded before you start working, Enmap provides a handy property called defer , which is a promise that is resolved once the provider is ready and all the data has been loaded into memory. There are a few ways to use defer , since it's a promise.

    Enmap-PGSQLarrow-up-right
    Enmap-Mongoarrow-up-right
    Enmap-Level:arrow-up-right
    // Load Enmap
    const Enmap = require('enmap');
    
    // Load EnmapSQLite
    const EnmapSQLite = require('enmap-sqlite');
    
    // Initialize the sqlite database with a table named "test"
    const provider = new EnmapSQLite({ name: 'test' });
    
    // Initialize the Enmap with the provider instance.
    const myColl = new Enmap({ provider: provider });
    
    // Persistent providers load in an **async** fashion
    // and provide a handy defer property:
    
    myColl.defer.then(() => {
        // all data is loaded now.
        console.log(myColl.size + "keys loaded");
    });
    
    // You can also await it if your function is async: 
    (async function() {
        await myColl.defer;
        console.log(myColl.size + "keys loaded");
        // Do stuff here!
    }());
    
    // Persistent collections should be **closed** before shutdown: 
    await myColl.db.close();

    Array Methods

    While Enmap is a Map enhanced with Array methods, Enmap also offers some enhanced array methods for the data stored inside of it. Talk about ArrayCeption!

    So what do I mean by methods for your stored data? I mean that you can store arrays inside Enmap, and directly push, pull, add and remove from those arrays. There are methods to work both on direct arrays, as well as arrays stored inside of an object.

    Let's take a look at two example entries in enmap that we can use. The first is a direct array, the second is an array inside an object.

    myEnmap.set("simpleArray", [1,2,3,4,5]);
    
    myEnmap.set("arrInObj", {
      name: "Bob",
      aliases: ["Bobby", "Robert"]
    });

    hashtag
    Adding to the array

    There are two methods to push to an array, one for simple arrays and one for arrays inside objects. Pushing in an enmap array is the same as a regular array push: it adds the element to the end of the array.

    The second parameter in pushIn is the "path" to the array in an object. It works the same as the properties path used in .

    hashtag
    Removing from the array

    Similarly, you can remove from an array. Note, however, that this will only work if you're removing a string or number. Removing an object from an array is not supported.

    myEnmap.push("simpleArray", 6);
    // now [1,2,3,4,5,6]
    
    myEnmap.push("arrInObj", "Robby", "aliases");
    // now ["Bobby", "Robert", "Robby"]
    myEnmap.remove("simpleArray", 2);
    // now [1,3,4,5,6]
    
    myEnmap.remove("arrInObject", "Bobby", "aliases");
    // now ["Robert", "Robby"]
    Working With Objects

    Mathematical Methods

    circle-exclamation

    This page is a work in progress and may not have the polish of a usual Evie-Written document!

    Some quick docs:

    hashtag
    enmap.math(key, operation, operator, [objectPath])

    Possible Operators (accepts all variations listed below, as strings):

    • +, add, addition: Increments the value in the enmap by the provided value.

    • -, sub, subtract: Decrements the value in the enmap by the provided value.

    hashtag
    enmap.inc(key, [objectPath])

    hashtag
    enmap.dec(key. [objectPath])

    Using Enmap.multi

    To account for people that might use a large number of enmaps in the same project, I've created a new `multi()` method that can be used to instanciate multiple peristent enmaps together.

    The method takes 3 arguments:

    • An array of names for the enmaps to be created.

    *, mult, multiply: Multiply the value in the enmap by the provided value.

  • /, div, divide: Divide the value in the enmap by the provided value.

  • %, mod, modulo: Gets the modulo of the value in the enmap by the provided value.

  • ^, exp, exponential: Raises the value in the enmap by the power of the provided value.

  • A Provider (not instanciated), from any of the available ones.
  • An options object containing any of the options needed to instanciate the provider. Do not add name to this, as it will use the names in the array instead.

  • Below, an example that uses destructuring:

    const Enmap = require('enmap');
    const Provider = require('enmap-mongo');
    const { settings, tags, blacklist, langs } = 
        Enmap.multi(['settings', 'tags', 'blacklist', 'langs'],
        Provider, { url: "mongodb://localhost:27017/enmap" });
    // Assuming
    points.set("number", 42);
    points.set("numberInObject", {sub: { anInt: 5 }});
     
    points.math("number", "/", 2); // 21
    points.math("number", "add", 5); // 26
    points.math("number", "modulo", 3); // 2
    points.math("numberInObject", "+", 10, "sub.anInt");
    // Assuming
    points.set("number", 42);
    points.set("numberInObject", {sub: { anInt: 5 }});
     
    points.inc("number"); // 43
    points.inc("numberInObject", "sub.anInt"); // {sub: { anInt: 6 }}
    // Assuming
    points.set("number", 42);
    points.set("numberInObject", {sub: { anInt: 5 }});
     
    points.dec("number"); // 41
    points.dec("numberInObject", "sub.anInt"); // {sub: { anInt: 4 }}

    Working with Objects

    Enmap is a great way to store structured data, and offers a few helper features that directly affect both objects and arrays.

    Let's assume for a moment that we want to store the following data structure in Enmap:

    This structure has 5 "properties": first, second, changeme, isCool, sub. The sub property has 2 properties of its own, yay and thing.

    To store this structure in Enmap, you can use a variable, or just straight-up write the object:

    Note: All further methods require the value to be an object. If you attempt to get, set, modify or remove using the below methods and your value isn't an object, Enmap will throw an error.

    hashtag
    Getting properties

    Retrieving a specific property from an object is done through the get() method, by specifying both the key and the "path" to the property you want.

    The exact method is <Enmap>.get(key, path).

    hashtag
    Checking if a property exists

    You can also check if a specific property exists or not. This is done through the has method, with a key, and path to the property:

    hashtag
    Modifying Properties

    There are a few various ways to modify properties of both Objects and Arrays. The very basic way to set a property on an object or array is through .set(key, value, path) like the following examples:

    As you can see, setProp() and getProp() work on the same concept that the path can be as complex as you want.

    Arrays have additional helper methods, .

    const myStructure = {
      first: "blah",
      second: "foo",
      changeme: "initial",
      isCool: false
      sub: {
        yay: true,
        thing: "amagig"
      }
    }
    you can see them here
    myEnmap.set("someObject", myStructure);
    
    // Or directly the object
    myEnmap.set("someObject", {first: "blah", ...});
    
    // Works with arrays, too!
    myEnmap.set("someArray", ["one", "two", "three"]);
    const second = myEnmap.get("someObject", "second");
    // returns "foo"
    
    const thing = myEnmap.get("someObject", "sub.thing");
    // returns true
    
    // The path can be dynamic, too: 
    const propToGet = "thing";
    const blah = myEnmap.get("someObject", `sub.${propToGet}`);
    myEnmap.has("someObject", "sub.thing"); // returns true
    
    myEnmap.has("someObject", "heck"); // returns false.
    // Set an object property
    myEnmap.set("someObject", "sub.blah", "newThing");
    
    // Set an array property
    myEnmap.set("someArray", "four", 3);

    Usage Documentation

    Inside your script, initialize a new Enmap:

    const Enmap = require("enmap");
    
    // Initialize an instance of Enmap
    const myCollection = new Enmap();
    
    // Adding data is simply a `set` command: 
    myCollection.set("myKey", "a value");
    
    // Getting a value is done by key 
    let result = myCollection.get("myKey");

    Using the fetchAll option

    As described in the home page, one disadvantage of Enmap is that it loads all your data in memory, so you're sacrificing RAM in order to gain speed. In larger projects, this might become a concern fairly quickly - or when using larger data sets that take more memory.

    For this purpose, I surrepticiously added a new option somewhere around Enmap 2.0 called "fetchAll", which defaults to "true" if you don't specify it - which is the old behaviour, and current default at the same time. But, if you set fetchAll to false in the Enmap options, data is not fetched on load.

    hashtag
    What does it mean if the data isn't loaded?

    If fetchAll is set to false, no data (by default) will be loaded from the database - the Enmap will be completely empty. This means that doing a .size check returns 0, looping and filtering doesn't return anything, and get() requests all return null.

    Ok but... how's that useful? It's useful because if you don't need the data, it's not loaded. To load data, there are 2 different methods available.

    hashtag
    Fetching Data

    • enmap.fetchEverything() will, of course, fetch all the data from the database - this is the method that's called on init() if fetchAll is true. This means you can stagger your loading time, or that you can decide, later, under certain conditions, you do want to load everything.

    • enmap.fetch(key) can fetch a single key from the database, saves it to enmap, and returns a promise with the fetched value.

    hashtag
    That's it!

    Yup. Those are the only things you really need to know for the current version of Enmap's fetchAll feature.

    hashtag
    Upcoming Features:

    I'm working on the following features in future versions of enmap, related to fetch methods:

    • Add the ability to check if the DB has a key without fetching

    • Add a method to uncache a key from enmap

    • Add a method to count keys in the DB (like enmap.keyCount() maybe?)

    enmap.fetch([array, of, keys]) will fetch each key in the requested array, and return an array of [key, value] pairs for each fetched value.
    Figure out how to "fetch on query" without breaking the nonblocking nature of enmap.