node.js+express+mongo環境にmongooseを使う

すでにmongoDBが起動しているモノとして書きます。

mongoDBってなんやねん?と言う人は先にMongoDBについて調べた方がいいかもです。

mongooseとは

モンゴーズと呼んでいましたが調べたらマングースでした。この手のライブラリの命名はシャレがきいてて面白いですよね。

そんなことはさておき、mongooseとはnode.jsでmongoにアクセスしたり保存したりするのをとても簡単にしてくれるライブラリです。

それだけではなくSchema(スキーマ)というモノがあり。mongoで取り扱うデータを事前に取りきめる事が可能です。もちろん型も設定できます。

MySQLを使われている人はそんなん当たり前やんと思うかも知れませんが、mongoでは何でも入っちゃいます。

間違えて入れちゃっても入っちゃいます。本当に全部入っちゃうんです(真剣

前置きはされおき早速触っていきましょう。

環境

まずは毎度のことで環境確認します。

これをしてくれないサイトが多くて後々バージョン違いで書いてる通りに行かないことがあります(^_^;

$ node -v
v10.15.3

$ express --version
4.16.0

$ mongo --version
MongoDB shell version v3.6.1

$ mongod --version
db version v3.6.

なにはともあれexpress

$ express testApp --view=ejs
create : testApp/
create : testApp/public/
create : testApp/public/javascripts/
create : testApp/public/images/
create : testApp/public/stylesheets/
create : testApp/public/stylesheets/style.css
create : testApp/routes/
create : testApp/routes/index.js
create : testApp/routes/users.js
create : testApp/views/
create : testApp/views/error.ejs
create : testApp/views/index.ejs
create : testApp/app.js
create : testApp/package.json
create : testApp/bin/
create : testApp/bin/www
change directory:
$ cd testApp
install dependencies:
$ npm install
run the app:
$ DEBUG=testapp:* npm start

テスト用のアプリケーションが作成されました。

npm installをすることを忘れないでくださいね。

$ cd testApp/

$ npm install

mongooseを入れる

$ npm install mongoose
mongoose@5.5.1
added 22 packages from 17 contributors and audited 180 packages in 5.468s
found 0 vulnerabilities

入りました。簡単ですね。

早速app.jsを開いて見ましょう。

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

上の方がこんな感じになってるかと思います。

ここにmongooseも使う事を追記してあげます。

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var mongoose = require('mongoose');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

特にどこに書いても問題ないのですが、まぁこんな感じです。
それでは早速設定をしていきましょう。

まずはDBに接続します。

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var mongoose = require('mongoose');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var app = express();

mongoose.connect('mongodb://localhost:27017/testdb', { useNewUrlParser: true });

var appの下ぐらいにdbの接続先設定をします。

今回はidやpassの設定をしていない最小限の環境でいきます。

バージョンが上がって第2引数に{ useNewUrlParser: true }と入れるように変更されています。
なくても動きますが{ useNewUrlParser: true }を第2引数に書けというエラーが出るようになってます。

mongoose.connect('mongodb://localhost:27017/testdb', { useNewUrlParser: true });

解説をしていきます。

var mongoose = require('mongoose');
// mongooseというオブジェクトがこれで作成されます。

mongoose.connect('mongodb://localhost:27017/testdb', { useNewUrlParser: true });
//mongoose.connect();はデータベースへのアクセスするための記述です。

//'mongodb://localhost:27017/testdb'
//少し説明は省きますが 'mongodb://localhost:27017/' これはmongoDBの場所を指定しています。
//もちろん別のサーバーに置いてあるmongoDBも使おうと思えば使えます。(設定は変更する必要があります)
//セキュリティ上オススメはしませんが(^_^;

//'mongodb://localhost:27017/testdb'
//この後ろの「/testdb」はmongodbで使用するデータベース名になっています。
//testdbを任意の名前に変更して好きなDB名で使いましょう。

Schemaの設定をしよう

connect出来たら早速Schemaを作ってみましょう。

mongoにconnectしただけでは何も出来ないですからね(^_^;

mongoose.connectのすぐ下ぐらいにSchemaを書いていきましょう。

var Schema = mongoose.Schema;

var UserSchema = new Schema({
 name: String,
 age: Number,
 date: {
  default: Date.now,
  type: Date,
 }
});
var UserModel = mongoose.model('users', UserSchema);

とりあえず全部書きました。

var Schema = mongoose.Schema;

// まぁショートカットみたいなもんですよね(^_^;
var UserSchema = new Schema({
name: String,
age: Number,
date: {
default: Date.now,
type: Date,
}
});

//new Schema();でmongo内で取扱データの形式を決めます。
//見て頂いたらわかると思いますが、左がkeyで右が型です。
//これに該当しないデータはmongooseが入れてくれません。
//dateのようにデフォルトの数値なども設定することが可能です。*入力オブジェクトにkeyが存在しなかった場合defaultが入ります。
var UserModel = mongoose.model('users', UserSchema);
//mongoose.model('users', UserSchema);
//これはcollectionsにSchemaをセットするための設定です。紐付けているんですね。

//第1引数の'users'はcollections名です。頭文字が大文字でもcollectionが作成されるときは全て小文字になります。
//さらに勝手にsがつきます。もし'user'と書くと[users]というcollectionが作成されます。
//usersと書いてもuserssとかにはならないです。

//第2引数でSchemaをセットしています。

データを保存してみよう

var user = new UserModel();
user.name = 'ohira';
user.age = 34;
user.save();

このObject特有の書き方にまだ慣れないのですが1度理解すると便利です。

var user = new UserModel();
//これはsaveするためのオブジェクトを作っています。
//userに色々くっつけたり実行したりするわけです。

objectにkeyを指定して値をセットするだけです。
最後にuser.save();で保存されます。

save()という機能は既に定義されています。
userというオブジェクトに値を入れてsave()を実行するイメージです。

user.save(function(err) {
  if (err) { console.log(err); }
});

って書いてるおけばエラーが出たときに教えてくれます。

mongoにアクセスして保存されているか確認してみてください。

> use testdb

> db.users.find()
{ "_id" : ObjectId("5cb41c688dc1262d4ec2a6a5"), "date" : ISODate("2019-04-15T05:53:44.353Z"), "name" : "ohira", "age" : 34, "__v" : 0 }
"_V":0ってなんですか?という質問を受けたのですが、これはバージョニングという機能のために付いています。
mongooseがデータを書きかえる時などに配列の番号が間違ってないかを確認するためにmongooseが使ってます。

呼び出してみよう

UserModel.find({}, function(err, docs) {
  console.log(docs[0].name + ':' + docs[0].age);
});

これだけです。とても簡単に取り出す事が出来ます。

注意が必要なのが1点だけあります。

UserModel.find();
これは
var UserModel = mongoose.model('users', UserSchema);

このmodelのUserModelです。user.save();したオブジェクトではありません。

modelに直接問合せています。
第1引数はfind({})の中身になります。ここに検索したい内容を書いて行きます。

第2引数でデータが戻ってきます。errかdocsに別けられます。
docsの中身は配列で順番に入ってます。
もしsortなどのoptionを設定したい場合は

UserModel.find({}, {sort:{age: -1},limit:2}, function(err, docs) {
console.log(docs[0].name + ':' + docs[0].age);
});
と第2引数に指定します。

削除する

UserModel.remove({ name: 'ohira' }, function(err) {
  if(err) console.log(err);
});

findと同じです。データと取ってこないので戻り値のdocsが無いぐらいです。
だんだん説明することが無くなってきました(^_^;

UserModel.remove({}, function(err) {
if(err) console.log(err);
});

って書くと全部消えちゃうので注意してくださいね(

2019/04/16 追記

remove()をすると下記Warningが出てきました。

remove()は推奨されていないので、deleteOneかdeleteMenyかbulkWriteを使ってください。と言うことらしいです。

(node:25816) DeprecationWarning: collection.remove is deprecated. Use deleteOne, deleteMany, or bulkWrite instead.

1つだけ削除する場合はdeleteOneを使用します。

最初の1つ目が削除されます。

UserModel.deleteOne({name:'ohira'}, function(err) {
   if(err) console.log(err);
 });

該当データを全て削除する場合はdeleteManyを使用します。

UserModel.deleteMany({name:'ohira'}, function(err) {
   if(err) console.log(err);
 });

上書きする

UserModel.update({ name: 'ohira' }, { $set: {age: 35} }, { upsert: false, multi: true }, function(err) {
 if(err) console.log(err);
});

UserModel.update();は少し複雑に見えるかもしれません。
基本的な記述はmongoと一緒なので、そこまで難しいわけではありません。

第1引数の{ name: 'ohira' }はfindの検索と一緒です。
該当する項目が更新されます
{ $set: {age: 35} }これが実際に更新される内容になります。
第1引数で指定して第2引数で変更します。
この場合は{ name: 'ohira' }に該当するデータのageが35に変更されます。
第3引数はoptionです。
{ upsert: false, multi: true }

upsertはデータを更新しようとして、そのデータが無かったとき新規で作成します。

multiはデータが複数あったときtrueなら全て更新。falseだったら最初の1つだけ更新します。

第4引数のerr処理はもう説明しなくても大丈夫ですよね。

基本的な記述方法は以上になります。

基本的には上記に紹介した4つの書き方で、あとはmongoの記述と同じです。
mongooseはmongoを直接触っているような感じで使えてとても便利です。

いろいろ弄って遊んで見て下さい。

もし間違えているところやうまく行かなかった場合はTwitterなどで聞いて頂ければと思います。

あわせて読みたい