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 🙏

© 2026 – Pkg Stats / Ryan Hefner

firestore-schema-validator

v0.8.0

Published

Interface for creating models, schemas and validate data for Google Cloud Firestore.

Downloads

358

Readme

Firestore Schema Validator

Elegant object modeling for Google Cloud Firestore.

Inspired by mongoose and datalize.

Installation

Requires firebase-admine package.

npm install --save firestore-schema-validator

API Docs

DOCS.md

Usage

Schema & Model - Simple example

// UserModel.js
const { Model, schema, field } = require('firestore-schema-validator')

const userSchema = schema({
  firstName: field('First Name')
    .string()
    .trim(),
  lastName: field('Last Name')
    .string()
    .trim(),
  email: field('Email Address')
    .string()
    .email(),
})

class UserModel extends Model {
  // Path to Cloud Firestore collection.
  static get _collectionPath() {
    return 'users'
  }

  // Model Schema.
  static get _schema() {
    return userSchema
  }
}

Schema & Model - Robust example

// UserModel.js
const { Model, schema, field } = require('firestore-schema-validator')

const userSchema = schema({
  firstName: field('First Name')
    .string()
    .trim(),
  lastName: field('Last Name')
    .string()
    .trim(),
  password: field('Password')
    .string()
    .match(/[A-Z]/, '%s must contain an uppercase letter.')
    .match(/[a-z]/, '%s must contain a lowercase letter.')
    .match(/[0-9]/, '%s must contain a digit.')
    .minLength(8),
  email: field('Email Address')
    .string()
    .email(),
  emailVerificationCode: field('Email Verification Code')
    .string()
    .nullable(),
  birthDate: field('Birth Date')
    .date('YYYY-MM-DD')
    .before(
      moment()
        .subtract(13, 'years')
        .toISOString(),
      'You must be at least 13 years old.',
    ),
  options: field('Options')
    .objectOf({
      lang: field('Language')
        .oneOf([
          'en-US',
          'pl-PL'
        ])
        .default('en-US'),
    })
})

class UserModel extends Model {
  static get _collectionPath() {
    return 'users'
  }

  static get _schema() {
    return userSchema
  }

  // You can define additional methods...
  static async getByEmail(email) {
    return await this.getBy('email', email)
  }

  // ... or getters.
  get isEmailVerified() {
    return Boolean(this._data.emailVerificationCode)
  }

  get fullName() {
    return `${this._data.firstName} ${this._data.lastName}`
  }

  // this.toJSON() by default returns this._data,
  // but you might want to display it differently
  // (eg. don't show password in responses,
  // combine firstName and lastName into fullName, etc.)
  toJSON() {
    return {
      id: this._id, // ID of Document stored in Cloud Firestore
      createdAt: this._createdAt, // ISO String format date of Document's creation.
      updatedAt: this._updatedAt, // ISO String format date of Document's last update.
      fullName: this.fullName,
      email: this.email,
      isEmailVerified: this.isEmailVerified,
    }
  }
}

// Fired when new user is successfully created and stored.
UserModel.on('created', async (user) => {
  // eg. send Welcome Email to User
})

// Fired when user is successfully updated and stored.
UserModel.on('updated', async (user) => {
  // eg. log info to console
})

// Fired when user is succsessfully deleted.
UserModel.on('deleted', async (user) => {
  // eg. delete photos uploaded by User
})

// Fired during user.validate() if user.email has changed,
// but *before* actually validating and storing the data.
UserModel.prehook('email', (data, user) => {
  // eg. set emailVerificationCode
})

// Fired during user.validate() if user.email has changed,
// but *after* actually validating and storing the data.
UserModel.posthook('email', (data, user) => {
  // eg. send Email Verification Email to User
})

UserModel.posthook('password', (data, user) => {
  // eg. hash password to store it securely
})

Working with UserModel

const admin = require('firebase-admin')
const User = require('../UserModel.js')

// Initialize Firebase
admin.initailizeApp({
  // config
})

const user = await User.create({
  firstName: 'Jon',
  lastName: 'Doe',
  email: '[email protected]',
  password: 'J0nD03!@#',
  birthDate: '1990-01-10',
}) // => instance of UserModel

console.log(user.toJSON()) // =>
// {
//   id: 'x22sSpmaJek0CYS9KTsI'.
//   createdAt: '2019-06-14T15:46:55.108Z',
//   updatedAt: null,
//   fullName: 'Jon Doe',
//   email: '[email protected]',
//   isEmailVerified: false,
// }

user.firstName = 'J'
user.foo = 'bar' // Won't be stored as it's not defined in UserModel._schema
await user.save() // => instance of UserModel

console.log(user.toJSON()) // =>
// {
//   id: 'x22sSpmaJek0CYS9KTsI'.
//   createdAt: '2019-06-14T15:46:55.108Z',
//   updatedAt: null,
//   fullName: 'J Doe',
//   email: '[email protected]',
//   isEmailVerified: false,
// }

const fetchedUser = await UserModel.getByEmail('[email protected]') // => instance of UserModel

console.log(fetchedUser.toJSON()) // =>
// {
//   id: 'x22sSpmaJek0CYS9KTsI'.
//   createdAt: '2019-06-14T15:46:55.108Z',
//   updatedAt: null,
//   fullName: 'J Doe',
//   email: '[email protected]',
//   isEmailVerified: false,
// }

await fetchedUser.delete()

const nonExistingUser = await UserModel.getByEmail('[email protected]') // => null

Nesting Schema

field.arrayOf(fieldOrSchema) and field.objectOf(objectOfFieldsOrSchema) accept instances of Schema as an argument, so you can reuse repeatable schemas:

const { schema, field } = require('firestore-schema-validator')

const simplifiedAddressSchema = schema({
  street: field('Street')
    .string()
    .trim(),
  countryCode: field('Country')
    .oneOf([
      'US',
      'CA',
    ]),
  zipCode: field('ZIP Code')
    .string()
    .trim(),
})

const userSchema = schema({
  firstName: field('First Name')
    .string()
    .trim(),
  lastName: field('Last Name')
    .string()
    .trim(),
  mailingAddress: field('Mailing Address')
    .objectOf(simplifiedAddressSchema),
})

const companySchema = schema({
  name: field('Company Name')
    .string()
    .trim(),
  locations: field('Locations')
    .arrayOf(simplifiedAddressSchema),
})

TODO

  • Field.prototype.unique() that checks if the value provided to field is unique in the collection.