Using Cloud Firestore in Datastore Mode

Firestore is a NoSQL document database built for automatic scaling, high performance, and ease of application development. It is the newest version of Datastore and introduces several improvements over Datastore.

We recommend using Firestore in Datastore mode for databases that will be used primarily by App Engine apps. For more information about Firestore modes, see Choosing between Native Mode and Datastore mode.

This document describes how to use the Google Cloud Client Library to store and retrieve data in a Datastore mode database.

Prerequisites and setup

Follow the instructions in "Hello, World!" for Node.js on App Engine to set up your environment and project, and to understand how Node.js apps are structured in App Engine. Write down and save your project ID, because you will need it to run the sample application described in this document.

Clone the repository

Download (clone) the sample:

git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples
cd nodejs-docs-samples/appengine/datastore

Edit project configuration and set dependencies

In package.json, set @google-cloud/datastore as a dependency, which provides the functions to use Datastore mode.

{
  "name": "appengine-datastore",
  "description": "Sample for Google Cloud Datastore on Google App Engine.",
  "version": "0.0.1",
  "private": true,
  "license": "Apache-2.0",
  "author": "Google Inc.",
  "repository": {
    "type": "git",
    "url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git"
  },
  "engines": {
    "node": ">=8.0.0"
  },
  "scripts": {
    "start": "node app.js",
    "system-test": "repo-tools test app",
    "test": "npm run system-test"
  },
  "dependencies": {
    "@google-cloud/datastore": "^5.0.0",
    "express": "^4.16.4"
  },
  "devDependencies": {
    "@google-cloud/nodejs-repo-tools": "^3.3.0"
  },
  "cloud-repo-tools": {
    "test": {
      "app": {
        "msg": "Last 10 visits:"
      }
    },
    "requiresKeyFile": true,
    "requiresProjectId": true
  }
}

Application code

The sample application logs, retrieves, and displays visitor IPs. You can see that a log entry is a simple two-field class that is given the type visit, and is saved to Datastore mode using the Dataset save command. Then, the ten most recent visits are retrieved in descending order, using the Dataset runQuery command.

'use strict';

const express = require('express');
const crypto = require('crypto');

const app = express();
app.enable('trust proxy');

// By default, the client will authenticate using the service account file
// specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable and use
// the project specified by the GOOGLE_CLOUD_PROJECT environment variable. See
// https://github.com/GoogleCloudPlatform/google-cloud-node/blob/master/docs/authentication.md
// These environment variables are set automatically on Google App Engine
const {Datastore} = require('@google-cloud/datastore');

// Instantiate a datastore client
const datastore = new Datastore();

/**
 * Insert a visit record into the database.
 *
 * @param {object} visit The visit record to insert.
 */
const insertVisit = visit => {
  return datastore.save({
    key: datastore.key('visit'),
    data: visit,
  });
};

/**
 * Retrieve the latest 10 visit records from the database.
 */
const getVisits = () => {
  const query = datastore
    .createQuery('visit')
    .order('timestamp', {descending: true})
    .limit(10);

  return datastore.runQuery(query);
};

app.get('/', async (req, res, next) => {
  // Create a visit record to be stored in the database
  const visit = {
    timestamp: new Date(),
    // Store a hash of the visitor's ip address
    userIp: crypto
      .createHash('sha256')
      .update(req.ip)
      .digest('hex')
      .substr(0, 7),
  };

  try {
    await insertVisit(visit);
    const [entities] = await getVisits();
    const visits = entities.map(
      entity => `Time: ${entity.timestamp}, AddrHash: ${entity.userIp}`
    );
    res
      .status(200)
      .set('Content-Type', 'text/plain')
      .send(`Last 10 visits:\n${visits.join('\n')}`)
      .end();
  } catch (error) {
    next(error);
  }
});

const PORT = process.env.PORT || 8080;
app.listen(process.env.PORT || 8080, () => {
  console.log(`App listening on port ${PORT}`);
  console.log('Press Ctrl+C to quit.');
});

Using index.yaml files

The sample app performs simple queries. More elaborate Datastore mode queries require one or more indexes, which you must specify in an index.yaml file that you upload along with your app. This file may be created manually, or generated automatically while testing your app locally.

Local testing

If you need to develop and test your application locally, you can use the Datastore mode emulator.

For more information

For complete information on Datastore mode, including optimizations and concepts, see the Cloud Firestore in Datastore mode documentation.

Was this page helpful? Let us know how we did:

Send feedback about...

App Engine flexible environment for Node.js docs