Node.js

なんだかよく分からないけどgetやpostのルート指定してるのにタイムアウトになる

var express = require('express');
var app = express();
app.get('/api/party.json', function(req, res){
    res.end();
});

res.end()を指定しないとタイムアウトになります。

expressでのgetの取得方法

function(req, res){
    req.query; //getのデータがオブジェクトの状態で入っている
};

MongoDBと連携したい

MongoDBのインストールについてはこちら


mongoose以外の方法もあります→GitHub - christkv/node-mongodb-native: Mongo DB Native NodeJS Driver

var mongoose = require('mongoose');
var db = mongoose.createConnection('mongodb://localhost/DB名');
var schema = new mongoose.Schema({
        name:String,
        text:String
});

module.exports = db.model('コレクション名', schema);
  1. mongooseをnpmで入れる
  2. DB名のところでこのアプリで使うDB名を決める。
  3. new mongoose.Schemaで型を指定する。
  4. db.modelでコレクション名指定


db.modelで生成されたオブジェクトにキーを追加すると使用時にエラーになる可能性があるので注意。

use DB名
db.コレクション名s.find()

mongoコマンドでアクセスする時は「DB名.コレクション名s」になる。コレクション名の後ろに「s」がつくことに注意。

var Db = require('上のコード');

//保存
var db = new Db({hoge:''});
db.save();

//更新
//第一引数がSQLのWHERE、第二引数がSET、第三引数がオプション。オプションについてはよく分かっていない。
//第二引数に{$set:{}}を使わない場合、省略された値は消えてしまう模様。
//また、_idが第二引数に使われているとエラーになるかもしれないので注意
Db.update({'_id':ObjectId('')}, {hoge:'huga'}, {malti:false});

//全件取得
Db.find(function(error, items){
    //itemsに結果が入る
});

//値を限定して取得
Db.find({hoge:''}, function(error, items){});

//特定のキー名のみからデータを取得。SELECT hoge, ahu FROM Db WHERE hoge = '';みたいな形式
Db.find({hoge:''}, '_id huga ahu', function(){error, items});

//MongoDBの一意IDから取得
Db.findById('MongoDBが生成した一意id', function(error, item){});

//全件削除
Db.remove(function(){});

一癖あるよね。


findでの比較:MongoDBの集計機能が便利過ぎて泣けてくるお話し - Y's note
ありがたや。


参考:node.js から MongoDB にアクセス (Mongoose の紹介) - KrdLab's blog

配列に格納され、かつオブジェクトに入っている_idを元にデータを取得したい
var mongoose = require('mongoose');
var db = mongoose.createConnection('mongodb://localhost/db');
var schemaA = new mongoose.Schema({});
var schemaB = new mongoose.Schema({
        name:String,
        join:[
		{
			'id':{type: mongoose.Schema.Types.ObjectId, ref: 'A'}
		}
	]
});

var dbA = db.model('A', schemaA);//1
var dbB = db.model('B', schemaB);

複数のコレクションを使う時、_idでドキュメントを保存し、必要に応じてデータを取得したい時があると思います。そのような時のためにこれをメモします。


まず前提条件なのですが、上記コードの1の部分のように、db変数に格納された値に、あらかじめ複数のコレクションのスキーマ情報を食べさせておかなければなりません。これを行わないと、上手く動作しません。mongooseでデータを操作する処理をコレクション単位で分けて書いている場合、注意が必要です。


複数の_idを配列で格納するのは、上記例のjoinの部分です。typeで格納したいものが_idである事を明示し、refでどのスキーマの_idであるかを識別します。もしdb.modelでAというスキーマを指定していない場合、実行時に「MissingSchemaError: Schema hasn't been registered for model」というエラーが発生します。

dbB.findOne({_id:'Aコレクションの_id'})
		.populate('join.id')
		.exec(function(error, joins){
			joins;//{id:{/*スキーマAに格納された情報*/}}
		});

前提条件として、dbAに値を格納し、dbBにのjoinに配列でdbA._idを保存した状態であるとします。
populateでjoin.idと指定すると、join[].idをdbA._idからdbAに格納された実際の値に置換を行います。


参考:
If I never try, I'll never know: Node.jsが面白い件⑥ MongoDBで遊ぶ 〜Mongoose編その③:サブドキュメントとリファレンス〜
Mongoose v5.5.1: Query Population
node.js - Mongoose populate within an object? - Stack Overflow

mongooseでfindを行おうとすると「TypeError: Object #\ has no method 'eachPath'」が発生する

mongooseで生成されたオブジェクトにキーを追加すると発生する。
キーを追加しない形にすればOK。

findなどで使える比較演算
演算子 用途 参考
$ne not equalの略称。それと一致しないものを返す {$ne:_id} MongoDB not equal to - Stack Overflow
$or 配列で条件を指定する。_idに対して$orは使えないらしい(Error: Can't use $or with ObjectId.) {$or:[{item:'どうのつるぎ'}, {item:'てつのつるぎ'}]} $and — MongoDB Manual
$set 値の更新。update時に$setを使用した場合、キー名が一致するものを更新し、その他のキーには何も行わない {$set:{item:'はがねのつるぎ'}}

socket.io

npm install socket.io

httpでlistenしたものをsocket.ioに渡さないとエラーになる。


サーバ側

var express = require("express");
var socketIO = require('socket.io');

var app = express();

app.use(express.static(__dirname + '/public'));

app.get("/", function(req, res){
        res.send("test");
});

var server = require('http').createServer(app);

server.listen(3000, function(){
        console.log("start");
});

var io = socketIO.listen(server);
io.sockets.on("connection", function(socket){
        console.log("connection");

        socket.on("message", function(data){
                console.log("message");
        });
});


クライアント側。
/socket.io/socket.io.jsをクライアント側に読み込ませることで、WebSocketが使用可能になる。
/socket.io/socket.io.jsはsocket.ioをインストールした時点で暗黙的に使用可能のようだ。

<button />
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect("ws://サーバのアドレス");

socket.on("connect", function(){
        console.log("接続"); 
});

socket.on("message", function(msg){
        console.log("サーバからのデータ受け取り");
});



$("button").click(function(){
        //サーバへのデータ送信
        socket.send(JSON.stringify({
                "test":"test"  
        }));
}); 

</script>
disconnectイベント
var express = require("express");
var socketIO = require('socket.io');

var app = express();

app.use(express.static(__dirname + '/public'));

app.get("/", function(req, res){
        res.send("test");
});

var server = require('http').createServer(app);

server.listen(3000, function(){
        console.log("start");
});

var io = socketIO.listen(server);
io.sockets.on("connection", function(socket){
        console.log("connection");

        //disconnectイベントはconnectionイベントの第一引数で設定しないといけない
        socket.on("disconnect", function(data){
                console.log("message");
        });
});


参考:
【初心者向け】node.js(0.10x) + socket.io(0.9x)のサンプルプログラム - 大人になったら肺呼吸
WebSocket 事始め by Node.js + Socket.IO - Qiita
http://mawatari.jp/archives/make-a-chat-application-in-node-js-and-websocket-io

セッションの共有

普通に使うとWebSocketのセッションとhttpのセッションは共有されない。


socket.io@1.0.3
express-session@1.2.1
express@4.4.0
cookie-parser@1.1.0

var express = require('express');
var cookieParser = require('cookie-parser');
var session = require("express-session");
var http = require('http');

var app = express();
//セッションを使う時はcookie-parserは必須
app.use(cookieParser());

const COOKIE = {
	//ここでインスタンスを生成するのが大事です!
	store: new session.MemoryStore,
	secret: 'SRX',
	cookie: {
		httpOnly: false
	}
};
app.use(session(COOKIE));

var server = http.createServer(app);
var io = require('socket.io').listen(server);
io.on("connection", function(socket){
	console.log("connection");
	
	socket.on("message", function(data){
		//ここでクッキー情報を取得
		var cookie = require('cookie').parse(socket.request.headers.cookie);	
		//何故かconnect.sidの値をそのまま使えないので、必要のない文字列を削る。
		cookie = cookie['connect.sid'].match(/s:([^.]*)\./)[1];

		//また、storeはappに食わせたものを使わないとgetは正しく動かない。
		COOKIE.store.get(cookie, function(error, session){
			//セッション取得!
			console.log(session);
		});
	});
});


参考:
Socket.IO と Express でセッションの共有 - Block Rockin’ Codes
GitHub - expressjs/session: Simple session middleware for Express



require("express-session").MemoryStore

store.get("expressが管理しているクッキーの情報", function(session){});でセッション情報を取得出来る。
が、取得されたデータを書き換える場合はstore.set("expressが管理しているクッキーの情報", session);としないと上書き保存はなされない。
jsの原理からすれば当然なのかもしれないが、ハマると結構大変。