我們知道,MongoDB 會(huì)自動(dòng)為每個(gè)文檔添加一個(gè)特殊的 _id 鍵,這個(gè) _id 鍵的值是經(jīng)過特殊計(jì)算的長(zhǎng)度為 24 的字符串的 ObjectId 對(duì)象(詳見《MongoDB 權(quán)威指南》),因此保證了每個(gè)文檔的 _id 都是獨(dú)一無二的。那我們可不可以使用 _id 鍵查詢一個(gè)獨(dú)一無二的文檔呢?當(dāng)然可以,這也是設(shè)計(jì) _id 的原因所在。
注意:使用 name 、day 、title 查詢一篇文章有個(gè)小 bug ,即不能在同一天發(fā)表相同標(biāo)題的文章,或者說發(fā)表了相同標(biāo)題的文章后只能返回最近發(fā)表的那篇文章。使用 _id 就可以很好的避免這個(gè) bug 。
下面我們舉例使用 _id 代替使用 name 、day 、title 來查詢一篇文章,即將:
app.get('/u/:name/:day/:title')
修改為以下形式:
app.get('/p/:_id')
打開 post.js ,在最上面添加:
var ObjectID = require('mongodb').ObjectID;
將:
Post.getOne = function(name, day, title, callback) {
修改為:
Post.getOne = function(_id, callback) {
并將 Post.getOne() 內(nèi)兩處的:
"name": name,
"time.day": day,
"title": title
都修改為:
"_id": new ObjectID(_id)
打開 index.js ,將 app.get('/u/:name/:day/:title') 修改如下:
app.get('/p/:_id', function (req, res) {
Post.getOne(req.params._id, function (err, post) {
if (err) {
req.flash('error', err);
return res.redirect('/');
}
res.render('article', {
title: post.title,
post: post,
user: req.session.user,
success: req.flash('success').toString(),
error: req.flash('error').toString()
});
});
});
注意:我們將文章頁(yè)面的路由修改為 app.get('/p/:_id') 而不是 app.get('/u/:_id') 是為了防止和上面的用戶頁(yè)面的路由 app.get('/u/:name') 沖突,況且,p 也代表 post ,表示發(fā)表的文章的意思。
打開 index.ejs ,將:
<p><h2><a href="/u/<%= post.name %>/<%= post.time.day %>/<%= post.title %>"><%= post.title %></a></h2>
修改為:
<p><h2><a href="/p/<%= post._id %>"><%= post.title %></a></h2>
現(xiàn)在,運(yùn)行你的博客并發(fā)表一篇文章,從主頁(yè)點(diǎn)擊標(biāo)題進(jìn)入該文章頁(yè)面,就變成了以下的 url 形式:
http://localhost:3000/p/52553dcd5bb408ec11000002
注意:MongoDB 數(shù)據(jù)庫(kù)中是以以下形式存儲(chǔ) _id 的:
"_id" : ObjectId("52553dcd5bb408ec11000002")
我們可以直接使用 post._id 從數(shù)據(jù)庫(kù)中獲取 _id 的值(24 位長(zhǎng)字符串),但在查詢的時(shí)候,要把 _id 字符串包裝成 MongoDB 特有的 ObjectId 類型。
讀者可依此類推,自行將剩余的工作完成。