0

I'm using the following Node.JS Plugin that allows you to use a LMDB in a Node app: https://github.com/Venemo/node-lmdb

As you can see, you can use cursors here but when I go through the cursor I get the results ordered by key and I want to get them chronologically, the first I instered to the last.

Is there anyway it can be done?

Thanks!

Yind
  • 335
  • 3
  • 17

1 Answers1

0

What you can do is create a new database where the keys are integers (in chronological order). It would look something like this:

var lmdb = require("node-lmdb");

var env = new lmdb.Env();

env.open({
  // Path to the environment
  path: "./path/to/db",
  // Maximum number of databases
  maxDbs: 10
});

var foo = env.openDbi({
   name: "foo",
   create: true
});

var fooChronological = env.openDbi({
   name: "foo-chronological",
   create: true,
   // This is needed in order to implement chronological sorting
   keyIsUint32: true
});


function getMax(txn) {
  // This is the number of records we've created so far
  var max = txn.getNumber(foo, "max");

  // If the max doesn't exist yet, default to 0
  if (max == null) {
    return 0;

  } else {
    return max;
  }
}

function setMax(txn, max) {
  txn.putNumber(foo, "max", max);
}


// Create a new record
function newRecord(txn, key, value) {
  var max = getMax(txn);

  // Put the record into the foo db
  txn.putString(foo, key, value);

  // Put the key into the fooChronological db in chronological order
  txn.putString(fooChronological, max, key);

  // Increment the max
  setMax(txn, max + 1);
}


function each(txn, db, f) {
  var cursor = new lmdb.Cursor(txn, db);

  try {
    var found = cursor.goToFirst();

    while (found != null) {
      cursor.getCurrentString(f);

      found = cursor.goToNext();
    }

  } finally {
    cursor.close();
  }
}


function eachChronological(txn, f) {
  each(txn, fooChronological, function (_, key) {
    f(key, txn.getString(foo, key));
  });
}


var txn = env.beginTxn();

newRecord(txn, "test", "1");
newRecord(txn, "abc", "2");
newRecord(txn, "z", "3");
newRecord(txn, "cde", "4");
newRecord(txn, "ghc", "5");
newRecord(txn, "foo", "6");
newRecord(txn, "bar", "7");
newRecord(txn, "qux", "8");
newRecord(txn, "corge", "9");
newRecord(txn, "yes", "10");
newRecord(txn, "no", "11");

// This prints it in lexiographical order
each(txn, foo, console.log);

// This prints it in chronological order
eachChronological(txn, console.log);

txn.commit();

There's some other ways too, for example you could store the chronological integer in the key itself, then you only need one database:

var lmdb = require("node-lmdb");

var env = new lmdb.Env();

env.open({
  // Path to the environment
  path: "./path/to/db",
  // Maximum number of databases
  maxDbs: 10
});

var foo = env.openDbi({
   name: "foo",
   create: true
});


function getMax(txn) {
  // This is the number of records we've created so far
  var max = txn.getNumber(foo, "max");

  // If the max doesn't exist yet, default to 0
  if (max == null) {
    return 0;

  } else {
    return max;
  }
}

function setMax(txn, max) {
  txn.putNumber(foo, "max", max);
}


function padLeft(str, num, fill) {
  return new Array(num - str.length + 1).join(fill) + str;
}


// Create a new record
function newRecord(txn, key, value) {
  var max = getMax(txn);

  // Put the record into the foo db
  // The padding length is 10 because 2147483647 is 10 characters long
  txn.putString(foo, padLeft("" + max, 10, "0") + key, value);

  // Increment the max
  setMax(txn, max + 1);
}


function each(txn, db, f) {
  var cursor = new lmdb.Cursor(txn, db);

  try {
    var found = cursor.goToFirst();

    while (found != null) {
      cursor.getCurrentString(f);

      found = cursor.goToNext();
    }

  } finally {
    cursor.close();
  }
}


var txn = env.beginTxn();

newRecord(txn, "test", "1");
newRecord(txn, "abc", "2");
newRecord(txn, "z", "3");
newRecord(txn, "cde", "4");
newRecord(txn, "ghc", "5");
newRecord(txn, "foo", "6");
newRecord(txn, "bar", "7");
newRecord(txn, "qux", "8");
newRecord(txn, "corge", "9");
newRecord(txn, "yes", "10");
newRecord(txn, "no", "11");

// This prints it in chronological order
each(txn, foo, function (key, value) {
  if (key !== "max") {
    console.log({ index: +key.slice(0, 10), key: key.slice(10), value: value });
  }
});

txn.commit();

In general if you want a different sort order then you will need to manipulate the key in some way.

Pauan
  • 2,506
  • 1
  • 20
  • 19