Open1

CRUDをnodejsとmongodbでやってみる

portgroundportground

前提

以下を導入済みとします。

この記事の対象

  • APIプログラミングに不慣れでいきなりAPIを使うのは、利用制限や課金が怖く気が引ける
  • nodejsを用いた定期的に何かを実行する処理の実装をざっくり知りたい

プロジェクト作成とパッケージインストール

npm init --yes
npm install express mongoose faker

モデルの定義と作成

今回は架空のイベント情報を格納するデータベースを作成する。
はじめにイベント情報として、イベント名・開始日時・開催状況の3つのフィールドを持つモデルを定義する。

Model.js
//Require Mongoose
const mongoose = require("mongoose")

//Define a schema
const eventSchema = new mongoose.Schema({
    eventName: {
        type: String
    },
    closingTime: {
        type: Date
    },
    isFinished: {
        type: Boolean
    }
})


class Event {
    static insertBulkData(data) {
        //mongoose Schema
        return this.insertMany(data)
    }
}

// methods from class into schema
eventSchema.loadClass(Event)

// Compile model from schema
module.exports = mongoose.model('Event', eventSchema)

参考:

CRUDをやってみる

Create編

今回の目的はあくまでCRUDなのでイベント情報は自動で生成する。
ここでは、fakerでランダムに生成したデータをMongoDBに挿入する。

fakerによる挿入データのランダム生成
※eventNameなどのキー名はModel.jsで定義したschemaのものと一致させる。

let record = {
 eventName: `${faker.address.city()} ${faker.animal.type()} festival`,
 closingTime: faker.date.soon(),
 isFinished: false
}

全体

index.js
const express = require('express');
const mongoose = require('mongoose');
const app = express();
const faker = require('faker');
const model = require('./Model')

mongoose.connect('mongodb://localhost:27017/nodeschedulerExample').then((res) => {
    console.log('mongoose connected successfully');
    app.get("/insertdata", async (req, res) => {
        let data = []
        for (let i = 0; i < 100; i++) {
            let record = {
                eventName: `${faker.address.city()} ${faker.animal.type()} festival`,
                closingTime: faker.date.soon(),
                isFinished: false
            }
            data.push(record)
        }
        await model.insertBulkData(data)

        res.send("Data is inserted")
    })
    app.listen(4000, () => {
        console.log("Server is running port 4000");
    })
}).catch((err) => {
    console.error(err);
})

Createの実行

ブラウザで以下のURLを開く。
http://localhost:4000/insertdata
実行に成功するとData is insertedと表示される。

次にデータを確認するため、MongoDB Compassを開く。
nodeschedulerEventDataというデータベースが新規作成され、
その中にeventsというコレクションが新規作成される。

Update編

Updateの実装

架空のイベント情報として、以下のようにモデルを定義しました。

Model.js
const eventSchema = new mongoose.Schema({
    eventName: {
        type: String
    },
    closingTime: {
        type: Date
    },
    isFinished: {
        type: Boolean
    }
})

このうちclosingTimeとisFinishedを用いて、
closingTimeが現在時刻を過ぎたイベントに終了フラグ(isFinishedをtrue)を設定」
という更新(Update)を実装します。

今回は先程のCreateのように、手動で実行するのではなくCronを使って自動で定期実行します。

パッケージを追加でインストール

npm install node-cron

このnode-cronを使ってスケジューラーを実装します。
scheduler.jsというファイルを新規作成します。

scheduler.js
const mongoose = require('mongoose');
const model = require('./Model');
const cron = require('node-cron');


mongoose.connect('mongodb://localhost:27017/nodeschedulerExample').then((res) => {
    console.log('mongoose connected successfully');
    cron.schedule("*/20 * * * * *", async () => {
        console.log("スケジューラータスクを実行")
    })

}).catch((err) => {
    console.error(err);
})

データベースからclosingTimeが現在時刻を過ぎたイベントを探し、
ステータスを更新するメソッドをEventクラスに追加します。

Module.js
    static archivEvent(date){
        
        return this.updateMany({
            closingTime : {
                '$lte' :new Date(date)
            }
        },{
            $set : {
                isFinished : true
            }
        }).exec();
    }

スケジューラーと組み合わせ、Updateを定期的に実行します。
closingTimeがスケジューラー実行時点より前の場合にアップデートされます。
動作確認のため、実行間隔は短めの20秒にしてます。

scheduler.js
const mongoose = require('mongoose');
const model = require('./Model');
const cron = require('node-cron');


mongoose.connect('mongodb://localhost:27017/nodeschedulerExample').then((res) => {
    console.log('mongoose connected successfully');
    cron.schedule("*/20 * * * * *", async () => {

        console.log("スケジューラータスクを実行します")
        const d = new Date();
        console.log(`次の日時より前のイベントをアーカイブ:${d}`)
        const result = await model.archiveEvent(d)

        const modifiedCount = result.modifiedCount
        console.log(`一致:${modifiedCount}`)
        if (modifiedCount > 0) {
            console.log(`scheduler => 終了したイベントをアーカイブしました`);
        }
    })

}).catch((err) => {
    console.error(err);
})

Updateの実行

スケジューラーを起動します。

node scheduler.js

20秒間隔でメッセージが表示され、Updateが自動で実行されます。
今回はclosingTimeとしてfaker.date.soon()を用いて日付をランダムに生成していますが、これは数時間〜数日後となっているので、少しずつUpdateされていくはずです。

もし中々Updateされない場合Createを担うプログラムを起動します。

node index.js

起動したらhttp://localhost:4000/insertdataより、データを増やしてみてください。

Delete編

Deleteの実装

先程のUpdate編では終了時間(closingTime)が過去のデータに終了フラグ(isFinished)を設定する処理をスケジューラーによる自動化した。

これに加え、一定の期間が経ったデータを削除する処理を実装する。

現在作成中…


参考サイト
Implementing Job Schedulers in Node.js