第6章 我的瓶子 - nswbmw/N-drifter GitHub Wiki
我们在玩漂流瓶的时候,捡到过的漂流瓶可以到 "我的瓶子" 里查看,下面我们来实现这个功能。
我们设定:捡到的漂流瓶可以长久保存,除非自己删除。我们使用 MongoDB 来实现数据持久化存储。
打开 package.json ,添加对 mongoose 的依赖:
{
"name": "drifter",
"version": "0.0.1",
"dependencies": {
"express": "^3",
"redis": "*",
"node-uuid": "*",
"generic-pool": "*",
"mongoose": "*"
},
"devDependencies": {
"request": "*"
}
}
并 npm install
安装 mongoose 包。
打开 app.js ,在上面添加一行代码:
var mongodb = require('./models/mongodb.js');
将 app.get('/')
修改为:
app.get('/', function (req, res) {
if (!req.query.user) {
return res.json({code: 0, msg: "信息不完整"});
}
if (req.query.type && (["male", "female"].indexOf(req.query.type) === -1)) {
return res.json({code: 0, msg: "类型错误"});
}
redis.pick(req.query, function (result) {
if (result.code === 1) {
mongodb.save(req.query.user, result.msg, function (err) {
if (err) {
return res.json({code: 0, msg: "获取漂流瓶失败,请重试"});
}
return res.json(result);
});
}
res.json(result);
});
});
以上代码的意思是:我们在捡到一个瓶子后,同时将该瓶子放到 "我的瓶子" 里(即存到 MongoDB 中)。我们将存入 MongoDB 的文档设置为以下形式:
{
bottle: ["$picker"],
message: [
["$owner", "$time", "$content"]
]
}
这样设置是为了方便实现后面的漂流瓶聊天功能,下一小节将会介绍。其中,bottle 数组第一项存储了捡瓶子的用户。message 数组存储了漂流瓶的原始信息(数组),数组第一项为漂流瓶的主人,第二项为扔瓶子的时间,第三项为漂流瓶的内容。
对应在 models 文件夹下新建 mongodb.js ,添加如下代码:
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/drifter', {server: {poolSize: 10}});
// 定义漂流瓶模型,并设置数据存储到 bottles 集合
var bottleModel = mongoose.model('Bottle', new mongoose.Schema({
bottle: Array,
message: Array
}, {
collection: 'bottles'
}));
// 将用户捡到漂流瓶改变格式保存
exports.save = function(picker, _bottle, callback) {
var bottle = {bottle: [], message: []};
bottle.bottle.push(picker);
bottle.message.push([_bottle.owner, _bottle.time, _bottle.content]);
bottle = new bottleModel(bottle);
bottle.save(function (err) {
callback(err);
});
};
这里我们将漂流瓶的信息存到了 MongoDB 的 drifter 数据库的 bottles 集合里了,并设置连接池大小为 10。关于如何配置和启动 MongoDB 前面有过介绍,这里不再赘述。
现在,当一个用户捡到一个瓶子的时候,该漂流瓶信息会自动存储到 MongoDB 中持久化保存。接下来我们实现当用户点击 "我的瓶子" 时获取全部瓶子的功能。
打开 app.js ,在 app.listen(3000);
前添加如下代码:
// 获取一个用户所有的漂流瓶
// GET /user/nswbmw
app.get('/user/:user', function (req, res) {
mongodb.getAll(req.params.user, function (result) {
res.json(result);
});
});
以上代码的意思是:当用户点击 "我的瓶子" 时,发送请求到服务器并返回该用户捡到的所有漂流瓶。
注意:我们并没有添加对用户的认证,即看起来任何人都可以获取任一用户的漂流瓶列表,这个工作可以在客户端完成。
打开 mongodb.js ,在最后添加如下代码:
// 获取用户捡到的所有漂流瓶
exports.getAll = function(user, callback) {
bottleModel.find({"bottle": user}, function (err, bottles) {
if (err) {
return callback({code: 0, msg: "获取漂流瓶列表失败..."});
}
callback({code: 1, msg: bottles});
});
};
以上代码的意思是:查找数据库中所有文档,返回满足 bottle 数组中有一项为 user 的所有文档。
试想一种情况:用户 A 扔的漂流瓶被用户 B 捡到了,此时用户 B 的漂流瓶列表中应该有该漂流瓶,而用户 A 的漂流瓶列表中应该没有该漂流瓶(即使是自己扔的),除非用户 B 回复了该漂流瓶(下一小节会介绍)。这就是为什么我们往 MongoDB 中第一次存储文档时,只在 bottle 中存储 picker 而不存储 owner 。
接下来我们实现当点击其中一个漂流瓶时,获取该漂流瓶内容的功能。
打开 app.js ,在 app.listen(3000);
前添加如下代码:
// 获取特定 id 的漂流瓶
// GET /bottle/529a8b5b39242c82417b43c3
app.get('/bottle/:_id', function (req, res) {
mongodb.getOne(req.params._id, function (result) {
res.json(result);
});
});
以上代码的意思是:根据查询的漂流瓶 id (即文档的 _id
键值,因为我们在获取漂流瓶列表的时候返回的文档包含 _id
键)查找并返回该漂流瓶信息。
打开 mongodb.js ,在最后添加如下代码:
// 获取特定 id 的漂流瓶
exports.getOne = function(_id, callback) {
// 通过 id 获取特定的漂流瓶
bottleModel.findById(_id, function (err, bottle) {
if (err) {
return callback({code: 0, msg: "读取漂流瓶失败..."});
}
// 成功时返回找到的漂流瓶
callback({code: 1, msg: bottle});
});
};
这里我们使用 mongoose 中的 findById 方法查询特定 id 的漂流瓶,findById 的第一个参数可以是字符串或 ObjectId 对象。
至此,我们完成了 "我的瓶子" 的功能。