▪️今日のお悩み
- MongoDBで、groupbyとかdistinctとかどうするの?
- それをnode.jsで実装する場合はどうするの?
▪️解決
- MongoDBのaggregateを使う。
- node.jsでMongoDBを使う時は、monngooseを使う。
> まずは参考となるリンク集
こちらを読んでいき、実際にデータをフィルタさせていくと、なんとなくコツがつかめてきます。
-
MySQLに馴染んでいる人はこちらもどうでしょうか。MySQLのクエリをMongoのクエリに直してくれるというものです。
> MongoDBでaggregationする簡単なサンプル
> aggregationするデータの準備
- ちなみに、MongoDBでの日付の挿入は以下の通り
db.example.insert({"date":new Date(Date.now())});
- monngooseは、collectionを複数形で作成する必要があります。
後で出てきますが、以下のようにTopicモデルを作成すると、
MongoDB側のターゲットが「topic」かと思いきや「topics」になっているので、よくはまるので気をつけてください。
var TopicModel = mongoose.model('Topic', topicSchema);
- サンプルデータをinsertします
db.topics.insert(
[
{
posted_at: new Date(Date.now()),
posted_by: 'tanaka',
data: 'hogehoge',
room:'room_1',
topic_text:'Todays Weather',
},
{
posted_at: new Date(Date.now()),
posted_by: 'okamoto',
data: 'hogehoge',
room:'room_2',
topic_text:'Todays Weather',
},
{
posted_at: new Date(Date.now()),
posted_by: 'tanaka',
data: 'hogehoge',
room:'room_2',
topic_text:'Todays Weather',
},
{
posted_at: new Date(Date.now()),
posted_by: 'yamamoto',
data: 'hogehoge',
room:'room_1',
topic_text:'New Year',
},
{
posted_at: new Date(Date.now()),
posted_by: 'tanaka',
data: 'hogehoge',
room:'room_1',
topic_text:'Count Down',
},
]
)
- データをselectします
- prettyをつけてあげると、分かりやすいJSON形式で出力してくれます。
db.topics.find().pretty()
> Aggregationの実行
Aggregationは、unixのpipe "|" operatorに似ています。
- count
- posted_by毎の数
db.topics.aggregate([
{$group : {_id : "$posted_by", num : {$sum : 1}}}
])
{ "_id" : "yamamoto", "num" : 1 }
{ "_id" : "okamoto", "num" : 1 }
{ "_id" : "tanaka", "num" : 3 }
- group
- room毎にgroupby
db.topics.aggregate( [
{ $group : { _id : { room: "$room" }, profile: { $push: "$$ROOT" }} }
] ).pretty()
{
"_id" : {
"room" : "room_2"
},
"profile" : [
{
"_id" : ObjectId("5861f90669e5e0b2eb21f16c"),
"posted_at" : ISODate("2016-12-27T05:15:50.603Z"),
"posted_by" : "okamoto",
"data" : "hogehoge",
"room" : "room_2",
"topic_text" : "Todays Weather"
},
{
"_id" : ObjectId("5861f90669e5e0b2eb21f16d"),
"posted_at" : ISODate("2016-12-27T05:15:50.603Z"),
"posted_by" : "tanaka",
"data" : "hogehoge",
"room" : "room_2",
"topic_text" : "Todays Weather"
}
]
}
{
"_id" : {
"room" : "room_1"
},
"profile" : [
{
"_id" : ObjectId("5861f90669e5e0b2eb21f16b"),
"posted_at" : ISODate("2016-12-27T05:15:50.603Z"),
"posted_by" : "tanaka",
"data" : "hogehoge",
"room" : "room_1",
"topic_text" : "Todays Weather"
},
{
"_id" : ObjectId("5861f90669e5e0b2eb21f16e"),
"posted_at" : ISODate("2016-12-27T05:15:50.603Z"),
"posted_by" : "yamamoto",
"data" : "hogehoge",
"room" : "room_1",
"topic_text" : "New Year"
},
{
"_id" : ObjectId("5861f90669e5e0b2eb21f16f"),
"posted_at" : ISODate("2016-12-27T05:15:50.603Z"),
"posted_by" : "tanaka",
"data" : "hogehoge",
"room" : "room_1",
"topic_text" : "Count Down"
}
]
}
- match+ group + sort
- room = room_1
- posted_atのソート
- topic_text毎
db.topics.aggregate( [
{ $match: { room : "room_1"}},
{ $sort: {posted_at:1}},
{ $group : { _id : { topic_text: "$topic_text" }, profile: { $push: "$$ROOT" }} }
] ).pretty()
{
"_id" : {
"topic_text" : "Count Down"
},
"profile" : [
{
"_id" : ObjectId("5861f90669e5e0b2eb21f16f"),
"posted_at" : ISODate("2016-12-27T05:15:50.603Z"),
"posted_by" : "tanaka",
"data" : "hogehoge",
"room" : "room_1",
"topic_text" : "Count Down"
}
]
}
{
"_id" : {
"topic_text" : "New Year"
},
"profile" : [
{
"_id" : ObjectId("5861f90669e5e0b2eb21f16e"),
"posted_at" : ISODate("2016-12-27T05:15:50.603Z"),
"posted_by" : "yamamoto",
"data" : "hogehoge",
"room" : "room_1",
"topic_text" : "New Year"
}
]
}
{
"_id" : {
"topic_text" : "Todays Weather"
},
"profile" : [
{
"_id" : ObjectId("5861f90669e5e0b2eb21f16b"),
"posted_at" : ISODate("2016-12-27T05:15:50.603Z"),
"posted_by" : "tanaka",
"data" : "hogehoge",
"room" : "room_1",
"topic_text" : "Todays Weather"
}
]
}
> monngoose+ node.jsでの実装
さて、上記のaggregateで実行したものをnode.jsで書きます。
npm install で mongoose をインストールして使います。
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//Database connection
var uristring = 'mongodb://localhost/jp';
var mongoOptions = { };
mongoose.connect(uristring, mongoOptions, function (err, res) {
if (err) {
console.log('Error when connecting to: ' + uristring + '. ' + err);
}
else {
console.log('Successfully connected to: ' + uristring);
}
});
//Schemas:
var topicSchema = new Schema({
posted_by: {
type: String,
default: ''
},
posted_at: {
type: Date,
default: Date.now
},
data: {
type: String,
default: JSON.stringify({})
},
room: {
type: String,
default: ''
},
topic_text: {
type: String,
default: ''
}
});
//Define Models
var TopicModel = mongoose.model('Topic', topicSchema);
getTopicProfile("room_1", function(err, data){
if(!err){
console.log(JSON.stringify(data));
}
});
//Aggregation function
function getTopicProfile(room_name, callback) {
TopicModel.aggregate([
{ $match: {
room: room_name
}},
{ $sort: {posted_at:1}},
{ $group: {
_id : { topic_text: "$topic_text" },
profile: { $push: "$$ROOT" }
}
}
], function (err, result) {
if (err) {
console.log(err);
return;
}
console.log(JSON.stringify(result));
});
}
- コードはこちらを参考にさせていただきました。