MongoDB で 自動インクリメント シーケンス を 作成する 方法

0 件のコメント

今回は「MongoDB で 自動インクリメント シーケンス を 作成する 方法」についてまとめます。

MongoDB は デフォルト で シーケンス が存在しないので、今回のサンプルのように自作することになります。 今回は簡単なサンプルとして2通りの方法を紹介します。

概要

基本的に MongoDB では多数のドキュメントを扱うため任意のフィールドにインクリメントを行うようなことは行いません。 デフォルトで _idObjectId のユニークキーが生成されるのでこちらを使います。

とはいえ、システム上ユニークな連番が必要なこともあるかと思います。 今回はユニークな番号を発番する方法を2通り紹介します。

いずれの方法においても以下のようなドキュメントで userid にシーケンスを発番する方法をサンプルコードとして載せます。

データベース test
コレクション users
ドキュメント { userid, name }

カウンターコレクションを利用する方法

{key: string, seq: number} のフォーマットとなる counters コレクションを作っておき、 シーケンスが必要なドキュメントを挿入する際にこの counters ドキュメントから最大値を取得したうえで更新することで自動インクリメントを実現する方法です。

前提

counters コレクションを作成します。 以下のサンプルは mongo コマンドから実行しています。

> db.counters.createIndex({ key: 1 }, { unique: true })
> db.counters.insertOne({ key: "userid", seq: 0 })

作成結果は以下のようになります。

> db.counters.find({}, { _id: 0 })
{ "key" : "userid", "seq" : 0 }

ソース (index.js)

var MongoClient = require("mongodb").MongoClient;

const CONNECTION_STRING = "mongodb://localhost:27017/test";

// シーケンス用コレクションを利用したシーケンス発番
var insertUser = function (userinfo, callback) {
  MongoClient.connect(CONNECTION_STRING).then((db) => {
    // カウンターコレクションからシーケンスを取得
    db.collection("counters").findOneAndUpdate(
      { key: "userid" },
      { $inc: { seq: 1 } },
      { upsert: true, returnOriginal: true },
      (err, doc) => {
        // シーケンス番号を設定
        userinfo.userid = doc.value.seq;

        // ドキュメントの挿入
        db.collection("users").insertOne(userinfo, (err, res) => {
          callback && callback(err, res);
        });
      });
  }).catch((err) => {
    console.log(err.message);
  });
};

// 実際に挿入を行う
insertUser({
  name: "Tsuyoshi Tanaka"
});

insertUser({
  name: "Subaru Osawa"
});

実行

> node ./index.js

結果

> db.users.find({},{_id:0})
{ "name" : "Subaru Natsuki", "userid" : 0 }
{ "name" : "Tsuyoshi Tanaka", "userid" : 1 }

ループ処理を利用する方法

シーケンス用のコレクションを準備しない代わりに現在挿入されているデータから最大値を取得して次の番号を取得するようにします。

ソース (index.js)

var MongoClient = require("mongodb").MongoClient;

const CONNECTION_STRING = "mongodb://localhost:27017/test";

// 繰り返し処理を利用したシーケンス発番
var insertUser = function (userinfo, callback) {
  MongoClient.connect(CONNECTION_STRING).then((db) => {

    // 繰り返し処理
    var loop = function () {
      db.collection("users")
        .find({}, { _id: 0, userid: 1 })
        .sort({ userid: -1 })
        .limit(1)
        .toArray((err, docs) => {
          if (err) {
            callback && callback(err, null);
            return;
          }

          // シーケンスの生成
          var seq = docs.length > 0 ? docs[0].userid + 1 : 0;

          // シーケンスの設定
          userinfo.userid = seq;

          // ドキュメントの挿入
          db.collection("users").insertOne(userinfo, (err, res) => {
            // シーケンス番号が被った場合は再帰実行
            if (err && err.code === 11000) {
              loop();

              return;
            }
            callback && callback(err, res);
          });
        });
    };

    // 繰り返し処理の初回実行
    loop();
  });
};

// 実際に挿入を行う
insertUser({
  name: "Tsuyoshi Tanaka"
});

insertUser({
  name: "Subaru Natsuki"
});

利用

> node ./index.js

結果

> db.users.find({}, { _id: 0 })
{ "name" : "Subaru Natsuki", "userid" : 0 }
{ "name" : "Tsuyoshi Tanaka", "userid" : 1 }

今回は「MongoDB で 自動インクリメント シーケンス を 作成する 方法」についてまとめました。 参考になったでしょうか? 本記事がお役に立っていると嬉しいです!!

参考記事

最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!