npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

grimstone

v1.0.5

Published

Agnostic mass modifier of firestore collections.

Downloads

2

Readme

grimstone

Agnostic mass modifier of firestore collections.

Installation

npm i grimstone

Getting Started

Grimstone is a Class object due to needing to initialize the firestore database:

import Grimstone from "grimstone";

// It requires an Object parameter of firestore credentials on initialization:
const grimstone = new Grimstone(config);

config object is a 1:1 parallel of firebase credentials:

const config = {
  apiKey: "XXX",
  appId: "XXX",
  authDomain: "XXX",
  projectId: "XXX",
};
const grimstone = new Grimstone(config);

All above keys are required. You can either save this as a local file somewhere:

// A standalone config.js file
export default {
  apiKey: "XXX",
  appId: "XXX",
  authDomain: "XXX",
  projectId: "XXX",
};

^ Do not forget to flag the above file to .gitignore to prevent leaking API keys

Then import and use it:

import config from "../config";
import Grimstone from "grimstone";
const grimstone = new Grimstone(config);

Or use .env file syntax:

const grimstone = new Grimstone({
  apiKey: process.env.VUE_APP_APIKEY,
  appId: process.env.VUE_APP_APPID,
  authDomain: process.env.VUE_APP_AUTHDOMAIN,
  projectId: process.env.VUE_APP_PROJECTID,
});

Functions

async modifyCollection(collection, callback[, mergeData?])

grimstone.modifyCollection() will read all items within a given collection, pass them to a callback function, then rewrite (or overwrite) the entry in the database. It returns an Array of the document ids which pass (or the error message paired with id whenever failing).

| Param | Type | Default | Description | | :--------- | :--------- | :------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------: | | collection | String | null | The name of the collection to target, as in "users", "orders", etc. | | callback | Function | null | The callback function which receives the entry data as a parameter, then returns a result which is written back to the database | | mergeData | Boolean | true | When true, the callback return value is intuitively merged into the object. When false, the database entry is completely overwritten by the callback return |

Examples

We have a large database where we need to make a mass change to some key of every entry, like an email:

// First we import and initialize Grimstone with our credentials:
import config from "../config";
import Grimstone from "grimstone";
const grimstone = new Grimstone(config);

// We call modifyCollection on a specific collection, passing it's name and our own callback function:
let result = await grimstone.modifyCollection("orders", modifyItem);

// The callback function receives the current document. This callback should be synchronous, not async:
function modifyItem(item) {
  return {
    email: item.email.toLowerCase().trim(),
  };
}

In the above, we don't pass in any value in the return object except email because mergeData is true by default. A more in-depth look at what's happening:

function modifyItem(item) {
  console.log(item);
  /* This may be data like:
   *    {
   *       email: "[email protected]    ",
   *       license: "XXXXXX",
   *       productName: "Timelord"
   *    }
   */

  // When we use a return value like this:
  return {
    email: item.email.toLowerCase().trim(),
  };
  /* We're telling firestore that we only want to modify the key/values in the above
   * object. The object will be rewritten in the database as:
   *    {
   *       email: "[email protected]",
   *       license: "XXXXXX",
   *       productName: "Timelord"
   *    }
   */
}

When mergeData is false, then it opts for a complete rewrite of the database object:

let result = await grimstone.modifyCollection("orders", modifyItem, false);

function modifyItem(item) {
  console.log(item);
  /* This may be data like:
   *    {
   *       email: "[email protected]    ",
   *       license: "XXXXXX",
   *       productName: "Timelord"
   *    }
   */
  return {
    email: item.email.toLowerCase().trim(),
  };
  /* Since we're not merging (we're instead overwriting), the result in our database
   * will be the direct return value above:
   *    {
   *       email: "[email protected]",
   *    }
   */
}

async queryAndModifyCollection(options, callback[, mergeData?])

grimstone.queryAndModifyCollection() will read all items within a given collection, pass them to a callback function, then rewrite (or overwrite) the entry in the database. It returns an Array of the document ids which pass (or the error message paired with id whenever failing). Unlike modifyCollection, this function supports multiple query and sorting options.

| Param | Type | Default | Description | | :-------- | :--------- | :------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------: | | options | Object | null | An Object containing key/value pairs for collection, where, and other query methods | | callback | Function | null | The callback function which receives the entry data as a parameter, then returns a result which is written back to the database | | mergeData | Boolean | true | When true, the callback return value is intuitively merged into the object. When false, the database entry is completely overwritten by the callback return |

Options supported parameters

| Param | Type | Default | Description | | :------------ | :------- | :------ | -----------------------------------------------------------------------: | | collection | String | null | The name of the target collection | | where? | Array | [] | An Array or Array of Arrays containing parameters for a .where() query | | orderBy? | Array | [] | An Array containing parameters for an .orderBy() method | | orderByChild? | String | null | A String value for the .orderByChild() method | | orderByValue? | String | null | A String value for the .orderByValue() method | | orderByKey? | String | null | A String value for the .orderByKey() method | | limit? | Number | null | A number which limits the max number of queries returned |

Examples

We have a very large database where we need to make a mass change to some key of every entry, like an email. We want to query these by batch instead of processing the entire collection:

// First we import and initialize Grimstone with our credentials:
import config from "../config";
import Grimstone from "grimstone";
const grimstone = new Grimstone(config);

let options = {
  collection: "orders", // The name of collection
  where: [
    // Where queries can be a single Array, or Array of Arrays for multiple
    ["email", ">=", "a"],
    ["email", "<", "g"], // Equivalent to .where("email", "<", "g")
  ],
  orderBy: ["email", "asc"], // Equivalent to .orderBy("email", "asc")
  limit: 10,
};

// The below acts the same as modifyCollection, but will only receive 10 objects
// whose emails begin with characters between "a" and "f" in ascending order:
let result = await grimstone.queryAndModifyCollection(options, modifyItem);

// The callback function receives the current document and passes a key/value to merge:
function modifyItem(item) {
  return {
    email: item.email.toLowerCase().trim(),
  };
}

The above will have returned emails like:

It's important to note that comparators like < and > are by lexicographical value, which is case sensitive. The above example function will not have returned emails like the following:

You will instead need to process those separately:

let result = await grimstone.queryAndModifyCollection(
  {
    collection: "orders",
    where: ["email", "<", "G"],
  },
  modifyItem
);