本文簡(jiǎn)單的介紹了數(shù)據(jù)庫(kù),以及如何在 Node/Express 中應(yīng)用他們祝懂。之后展示如何使用Mongoose為一個(gè)圖書(shū)網(wǎng)站提供數(shù)據(jù)訪問(wèn)紊扬。介紹了Mongoose的模式和模型的聲明照瘾,主要屬性類(lèi)型,基礎(chǔ)校驗(yàn)器飘蚯。也展示了訪問(wèn)數(shù)據(jù)模型的幾種主要方法馍迄。
概括
圖書(shū)管理員將使用一個(gè) 圖書(shū)管理網(wǎng)站 去記錄書(shū)籍和借書(shū)人的信息,同時(shí)讀者會(huì)使用 圖書(shū)管理網(wǎng)站 去瀏覽搜索圖書(shū)局骤,去查看是不是某書(shū)全部借出攀圈,然后預(yù)約或直接借走該書(shū)。為了更有效率存儲(chǔ)信息峦甩,這里我們需要一個(gè)數(shù)據(jù)庫(kù)赘来。
Express提供了多種數(shù)據(jù)庫(kù)的支持,你有多種方式去實(shí)現(xiàn)增刪查改操作凯傲。本文簡(jiǎn)要的概述了一些可用的選項(xiàng)犬辰,并詳細(xì)說(shuō)明一些查詢(xún)的特殊機(jī)制。
使用什么數(shù)據(jù)庫(kù)冰单?
Express應(yīng)用可以使用Node支持的各種數(shù)據(jù)庫(kù)(Express本身對(duì)數(shù)據(jù)庫(kù)并沒(méi)有特殊要求)幌缝。常用的選項(xiàng)包括PostgreSQL,MySQL球凰,Redis狮腿,SQLite,MongoDB呕诉。
當(dāng)選擇一個(gè)數(shù)據(jù)庫(kù)時(shí)缘厢,我們需要考慮的常常有 時(shí)間成本,學(xué)習(xí)曲線甩挫,性能贴硫,備份和回滾的易用性,成本以及其社區(qū)支持情況伊者。雖然并沒(méi)有一個(gè)最好的數(shù)據(jù)庫(kù)英遭,但是對(duì)于我們的 圖書(shū)管理網(wǎng)站 這樣的小型網(wǎng)站,任何流行的數(shù)據(jù)庫(kù)都是可以的亦渗。
如何更好的與數(shù)據(jù)庫(kù)交互挖诸?
與數(shù)據(jù)庫(kù)交互有兩種方法:
- 使用數(shù)據(jù)庫(kù)的自帶的查詢(xún)語(yǔ)言(比如SQL)
- 使用對(duì)象數(shù)據(jù)模型("ODM")或?qū)ο箨P(guān)系模型 ("ORM")。一個(gè)ODM或ORM對(duì)象代表的就是一個(gè)映射到底層數(shù)據(jù)庫(kù)的數(shù)據(jù)對(duì)象比如說(shuō)JSON對(duì)象法精。一些ORM對(duì)象是指定數(shù)據(jù)庫(kù)的多律,一些則不然。
使用SQL語(yǔ)言或者其他數(shù)據(jù)庫(kù)支持的語(yǔ)言可以獲得很好的性能搂蜓。ODM則相對(duì)比較慢狼荞,因?yàn)樾枰a去轉(zhuǎn)換映射的對(duì)象和數(shù)據(jù)庫(kù)中的格式,所以他生成的查詢(xún)語(yǔ)句可能不夠高效(尤其是在ODM為了支持不同的數(shù)據(jù)庫(kù)后臺(tái)帮碰,這時(shí)必須對(duì)數(shù)據(jù)庫(kù)功能做出極大的妥協(xié))相味。
使用ODM的優(yōu)勢(shì)在于程序員可以一直關(guān)注與JavaScript 對(duì)象而不是數(shù)據(jù)庫(kù)語(yǔ)義,尤其是在你需要和不同的數(shù)據(jù)庫(kù)交互(可能是同一應(yīng)用殉挽,或不同應(yīng)用)丰涉。ODM也提供了清晰方式去校驗(yàn)檢查數(shù)據(jù)拓巧。
使用ODM或ORM可以降低開(kāi)發(fā)和維護(hù)成本,除非你非常擅長(zhǎng)原生查詢(xún)語(yǔ)言昔搂,或?qū)π阅芤蠛芨吡嵯駝t你都應(yīng)該優(yōu)先考慮使用ODM或ORM。
使用什么ODM/ORM
在npm中有許多ODM摘符、ORM贤斜。
在本文寫(xiě)作時(shí)幾個(gè)熱門(mén)的框架
- Mongoose:Mongoose是一個(gè)用于異步環(huán)境的MongoDB的對(duì)象模型。
- Waterline:提取自基于Express的Sail框架的對(duì)象關(guān)系模型逛裤。他為眾多數(shù)據(jù)庫(kù)提供了統(tǒng)一的API接口瘩绒,包括 Redis, mySQL, LDAP, MongoDB, 和 Postgres。
- Bookshelf:同時(shí)具備promise和傳統(tǒng)回調(diào)函數(shù)的接口带族,提供了對(duì)事務(wù)的支持锁荔,eager/nested-eager relation loading(不知道咋翻),集成多態(tài)蝙砌,支持 一對(duì)一阳堕,一對(duì)多,多對(duì)多關(guān)系择克。支持PostgreSQL, MySQL, 和 SQLite3恬总。
- Objection:盡可能的簡(jiǎn)化的使用數(shù)據(jù)庫(kù)和SQL的全部功能(支持SQLite3, Postgres 和 MySQL)
- Sequelize:基于promise的ORM...
在選擇解決方案時(shí)一般應(yīng)該考慮他們都提供哪些功能,以及他們社區(qū)的活躍度(下載肚邢,捐款壹堰,Bug報(bào)告,文檔質(zhì)量)骡湖。在此文寫(xiě)作時(shí)Mongoose當(dāng)前最受歡迎的ORM贱纠,如果你在你的應(yīng)用中使用MongoDB作為你的數(shù)據(jù)庫(kù),那么他是一個(gè)合理的選擇响蕴。
在LocalLibrary(這篇文章中的項(xiàng)目名)使用MongoDB和Mongoose
在本文中我們使用Mongoose來(lái)訪問(wèn)我們的圖書(shū)數(shù)據(jù)谆焊。Mongoose作為MongoDB的前端,MongoDB是一個(gè)開(kāi)源的NoSQL浦夷,使用面向文檔的對(duì)象模型的數(shù)據(jù)庫(kù)懊渡。在MongoDB中 集合(collection)中的文檔(documents)類(lèi)似于關(guān)系數(shù)據(jù)庫(kù)中的表(table)中的行(row)。
這對(duì)ODM和數(shù)據(jù)庫(kù)組合在Node的社區(qū)中是非常流行的军拟,部分原因是因?yàn)槲臋n存儲(chǔ)和查詢(xún)起來(lái)非常類(lèi)似于JSON,對(duì)于JS程序員這是非常熟悉的誓禁。
你不必為了使用Mongoose而去了解MongoDB懈息,但是如果你已經(jīng)了解MongoDB,可以更容易的使用和理解Mongoose
教程后續(xù)部分將講解如何為L(zhǎng)ocalLibrary定義以及使用Mongoose模板和模型摹恰。
LocalLibrary的model設(shè)計(jì)
當(dāng)你開(kāi)始進(jìn)行model編碼的時(shí)候辫继,花一些時(shí)間考慮你應(yīng)該需要存儲(chǔ)什么數(shù)據(jù)怒见,以及不同對(duì)象之間的關(guān)系。
我們知道我們需要存儲(chǔ)有關(guān)書(shū)籍的信息(書(shū)名姑宽,概要遣耍,作者,類(lèi)型炮车,書(shū)號(hào))舵变,而且一種書(shū)我們可能有多本(擁有唯一的ID,可用狀態(tài))瘦穆,我們可能也需要存儲(chǔ)除了姓名之外其他的作者信息纪隙,而且可能會(huì)有多個(gè)作者名是相同或相似的。我們還想能夠通過(guò) 書(shū)名扛或,作者绵咱,書(shū)的類(lèi)別進(jìn)行排序。
當(dāng)你設(shè)計(jì)你的Model時(shí)為不同的Object(擁有一組相關(guān)的信息的對(duì)象)設(shè)置不同的Model是必要的熙兔。在當(dāng)前的實(shí)例中明顯的對(duì)象有 書(shū)籍悲伶,書(shū)籍實(shí)體,作者住涉。
你可能也想為一個(gè)下拉列表選項(xiàng)新建一個(gè)Model麸锉。相對(duì)于硬編碼,當(dāng)下拉列表不確定或經(jīng)常更改秆吵,這種方式更加推薦淮椰。在本例中書(shū)籍類(lèi)型(科幻小說(shuō),法國(guó)詩(shī)歌)明顯就是屬于這種類(lèi)型纳寂。
一旦我們確定了Model和相應(yīng)的屬性主穗,我們就需要思考他們之間的關(guān)系。
考慮到這一點(diǎn)毙芜,下面的UML關(guān)系圖展示了當(dāng)前我們定義的Model迈喉。根據(jù)上文的討論,我們將為書(shū)籍(包含書(shū)籍的一般信息)艘绍,書(shū)籍實(shí)體(包含這本書(shū)在系統(tǒng)中的狀態(tài))侥猩,作者 創(chuàng)建Model。同時(shí)我們也決定為書(shū)籍的類(lèi)別創(chuàng)建一個(gè)Model隘冲,這樣書(shū)的類(lèi)別就可以動(dòng)態(tài)修改闹瞧。書(shū)籍實(shí)體的狀態(tài)并不常變化,我們不會(huì)為他單獨(dú)創(chuàng)建Model展辞。在每個(gè)方塊中我們定義了Model的名字奥邮,以及屬性名和類(lèi)型,還有方法名和方法返回值的類(lèi)型。
該圖也展示了Model直接的關(guān)系洽腺,和他們數(shù)量的對(duì)應(yīng)關(guān)系(最大和最薪潘凇)。比如在Book和Genre之間的連線蘸朋,在靠近Book的數(shù)字表示一本書(shū)有0或者多個(gè)Genre核无,而另一端的數(shù)字表示每個(gè)Genre有0或者多個(gè)Book
Mongoose入門(mén)
這部分概括了如何用Mongoose連接MongoDB,如何定義Schema(這個(gè)之前被我翻成模板藕坯,不知道對(duì)不對(duì)团南,后面索性不返了) 和Model,如何進(jìn)行簡(jiǎn)單的查詢(xún)堕担。
安裝Mongoose和MongoDB
Mongoose和其他的依賴(lài)一樣被安裝已慢,使用以下命令為你的項(xiàng)目安裝Mongoose。
npm install mongoose --save
安裝Mongoose會(huì)自動(dòng)加入他的依賴(lài)霹购,例如MongoDB的驅(qū)動(dòng)佑惠,但并沒(méi)有安裝MongoDB數(shù)據(jù)庫(kù)本身。如果你想要安裝MongoDB你可以從這里下載多個(gè)平臺(tái)的安裝包齐疙。你也可以使用云端的MongoDB實(shí)例膜楷。
提示:在本文中我們將使用mLab的云端作為數(shù)據(jù)庫(kù)。這樣非常適合開(kāi)發(fā)贞奋,對(duì)于這個(gè)教程這樣做也是有意義的赌厅,因?yàn)樗拱惭b過(guò)程不依賴(lài)讀者的操作系統(tǒng)。
連接到MongoDB
Mongoose會(huì)向MongoDB請(qǐng)求連接轿塔。你能夠使用require()引入Mongoose特愿,并使用mongoose.connect()連接到本地?cái)?shù)據(jù)庫(kù),如下所示:
//Import the mongoose module
var mongoose = require('mongoose');
//Set up default mongoose connection
var mongoDB = 'mongodb://127.0.0.1/my_database';
mongoose.connect(mongoDB);
//Get the default connection
var db = mongoose.connection;
//Bind connection to error event (to get notification of connection errors)
db.on('error', console.error.bind(console, 'MongoDB connection error:'));
用mongoose.connection你可以獲得Mongoose的默認(rèn)Connection 對(duì)象勾缭。一旦連接完成揍障,open 事件將從Connection 實(shí)例中發(fā)射。
提示:如果你需要額外的Connection俩由,你可以使用mongoose.createConnection()毒嫡,他接受一個(gè)和connect()相同格式的數(shù)據(jù)庫(kù)URI(包含host,數(shù)據(jù)庫(kù)名幻梯,端口兜畸,選項(xiàng)),返回一個(gè)Connection 實(shí)例碘梢。
定義并創(chuàng)建Model
Model是使用Schema 接口來(lái)定義咬摇。Schema 用來(lái)定義存儲(chǔ)在document 中的屬性,并且賦予他們校驗(yàn)的規(guī)則煞躬,和默認(rèn)值肛鹏。另外你可以定義靜態(tài) 或 實(shí)體 的helper方法,使你的數(shù)據(jù)類(lèi)型更加易于使用。你也可以定義像其他屬性一樣使用的虛擬屬性龄坪,這些屬性并不會(huì)被保存到數(shù)據(jù)庫(kù)中(這些會(huì)在后文中講解)。
Schema使用mongoose.model()去“編譯”入Model复唤。一旦擁有一個(gè)model 健田,你可以使用他用來(lái)創(chuàng)建,查詢(xún)佛纫,刪除指定的對(duì)象妓局。
Model對(duì)應(yīng)的是MongoDB中documents的collection,documents中包含在Schema中的定義的屬性和屬性對(duì)應(yīng)的類(lèi)型呈宇。
定義Schema
下面的代碼展示了如何定義一個(gè)簡(jiǎn)單的Schema好爬。首先引入mongoose,然后使用Schema的構(gòu)造方法新建一個(gè)Schema的實(shí)例甥啄,在構(gòu)造函數(shù)的參數(shù)對(duì)象中定義屬性存炮。
//Require Mongoose
var mongoose = require('mongoose');
//Define a schema
var Schema = mongoose.Schema;
var SomeModelSchema = new Schema({
a_string: String,
a_date: Date
});
在上面的例子中,我們只有兩個(gè)屬性蜈漓,一個(gè)字符串穆桂,一個(gè)時(shí)間。在本文的下一段我們會(huì)展示其他屬性類(lèi)型融虽,和校驗(yàn)器和其他方法享完。
創(chuàng)建一個(gè)Model
Model是使用mongoose.model()創(chuàng)建自Schema。
// Define schema
var Schema = mongoose.Schema;
var SomeModelSchema = new Schema({
a_string: String,
a_date: Date
});
// Compile model from schema
var SomeModel = mongoose.model('SomeModel', SomeModelSchema );
第一個(gè)參數(shù)是MongoDB中的集合的名有额,mongoose將為上面的Model創(chuàng)建一個(gè)名為SomeModel的集合般又。第二個(gè)參數(shù)是你想要用來(lái)創(chuàng)建Model的Schema 。
一旦你創(chuàng)建了Model巍佑,你可以使用他來(lái)進(jìn)行增刪查改茴迁,既可以查詢(xún)?nèi)坑涗洠部梢圆樵?xún)特定的子集句狼。當(dāng)我們創(chuàng)建我們的視圖時(shí)笋熬,我們會(huì)在“使用Model”段講解如何做。
Schema 中屬性的類(lèi)型
Schema 可以有任意數(shù)量的屬性腻菇,每一個(gè)屬性都代表了在MongoDB中的字段胳螟。下面的例子展示了常用的屬性類(lèi)型是如何被定義的。
var schema = new Schema(
{
name: String,
binary: Buffer,
living: Boolean,
updated: { type: Date, default: Date.now },
age: { type: Number, min: 18, max: 65, required: true },
mixed: Schema.Types.Mixed,
_someId: Schema.Types.ObjectId,
array: [],
ofString: [String], // You can also have an array of each of the other types too.
nested: { stuff: { type: String, lowercase: true, trim: true } }
})
大多數(shù)屬性類(lèi)型的意義是顯而易見(jiàn)的筹吐,除了以下幾項(xiàng):
- ObjectId:代表在數(shù)據(jù)庫(kù)中的一個(gè)對(duì)象實(shí)體糖耸,比如,書(shū)本對(duì)象可以使用他來(lái)代表他的作者丘薛。實(shí)際上他包含的是對(duì)象的唯一id(_id)嘉竟。我們可以在需要的時(shí)候使用populate()方法獲取某些信息。
- Mixed:任意schema類(lèi)型。
- []:數(shù)組對(duì)象舍扰。你可以對(duì)該對(duì)象執(zhí)行JavaScript數(shù)組操作(push, pop, unshift等)倦蚪。上面的實(shí)例展示了,沒(méi)有指定數(shù)組對(duì)象類(lèi)型的數(shù)組边苹,和指定為String的數(shù)組陵且。你可以指定任意類(lèi)型的數(shù)組。
這段代碼也展示來(lái)定義屬性的兩種方法:
- 屬性名和屬性類(lèi)型作為鍵值對(duì)个束。
- 屬性名后緊跟一個(gè)對(duì)象來(lái)定義屬性類(lèi)型慕购,以及屬性的其他選項(xiàng)。選項(xiàng)包含以下這些:
- 默認(rèn)值
- 內(nèi)置的校驗(yàn)器(min/max)茬底,或者定制的校驗(yàn)函數(shù)沪悲。
- 屬性是否是必須的。
- 屬性是否會(huì)自動(dòng)大寫(xiě)阱表,小寫(xiě)或者去除空格(e.g. { type: String, lowercase: true, trim: true })殿如。
更多有關(guān)選項(xiàng)的信息,請(qǐng)看SchemaTypes的文檔捶枢。
校驗(yàn)器
Mongoose提供來(lái)內(nèi)置的校驗(yàn)器握截,自定義校驗(yàn)器,同步或者異步校驗(yàn)器烂叔。他用來(lái)指定可用的范圍或者值谨胞,以及在校驗(yàn)失敗時(shí)的錯(cuò)誤信息。
內(nèi)置的校驗(yàn)器包括:
- 所有的類(lèi)型都包含required校驗(yàn)器蒜鸡。這個(gè)校驗(yàn)器是用來(lái)指定在保存時(shí)胯努,屬性是否是必須的。
- Numbers有min 和max校驗(yàn)器逢防。
- Strings類(lèi)型有:
下面的樣例略微修改自Mongoose的文檔忘朝,展示來(lái)如何指定校驗(yàn)器的類(lèi)型和錯(cuò)誤信息灰署。
var breakfastSchema = new Schema({
eggs: {
type: Number,
min: [6, 'Too few eggs'],
max: 12
required: [true, 'Why no bacon?']
},
drink: {
type: String,
enum: ['Coffee', 'Tea', 'Water',]
}
});
詳細(xì)的校驗(yàn)器說(shuō)明,請(qǐng)看Mongoose的文檔Validation
虛擬屬性
虛擬屬性是你可以get和set的對(duì)象屬性局嘁,但是他們不會(huì)被保存到MongoDB中溉箕。get方法常常被用來(lái)格式化或者合并屬性,set方法常用來(lái)分解單個(gè)屬性并把他們保存在數(shù)據(jù)庫(kù)中的多個(gè)屬性中悦昵。在本例中用first name和last name屬性去構(gòu)造一個(gè)全名肴茄,相對(duì)于每次在使用時(shí)來(lái)構(gòu)造一個(gè)全名更加清晰和簡(jiǎn)單。
備注:我們將使用虛擬屬性為每條記錄的_id屬性和地址定義一個(gè)唯一URL但指。
更多信息請(qǐng)看Virtuals
方法和查詢(xún)助手
schema可以有實(shí)體方法寡痰,靜態(tài)方法和查詢(xún)助手抗楔。實(shí)體方法和靜態(tài)方法是類(lèi)似的,他們之間明顯的不同是拦坠,實(shí)例方法是關(guān)聯(lián)到實(shí)際對(duì)象的连躏,能夠訪問(wèn)當(dāng)前對(duì)象。查詢(xún)助手允許你擴(kuò)展mongoose的查詢(xún)構(gòu)造器API(比如贞滨,你可以添加“byName”查詢(xún)方法去擴(kuò)展find(), findOne() 和 findById())反粥。
Model的使用
一旦你創(chuàng)建創(chuàng)建了schema,你就可以使用他來(lái)創(chuàng)建Model疲迂。Model代表了數(shù)據(jù)庫(kù)中Document的Collection,而一個(gè)Model的實(shí)體代表了一個(gè)你可以存取的單一對(duì)象莫湘。
下面我們提供一個(gè)概述尤蒿,詳情請(qǐng)看Models 。
創(chuàng)建和更改document
你可以通過(guò)創(chuàng)建一個(gè)Model實(shí)體并調(diào)用save()方法去保存一條記錄幅垮。下面的例子假設(shè)SomeModel是通過(guò)schema創(chuàng)建的某個(gè)對(duì)象(只有一個(gè)“name”屬性)腰池。
// Create an instance of model SomeModel
var awesome_instance = new SomeModel({ name: 'awesome' });
// Save the new model instance, passing a callback
awesome_instance.save(function (err) {
if (err) return handleError(err);
// saved!
});
注意記錄的創(chuàng)建(以及更新,刪除忙芒,查詢(xún))是異步操作示弓,你需要傳遞一個(gè)回調(diào)函數(shù),當(dāng)操作完成時(shí)會(huì)執(zhí)行呵萨。我們遵從錯(cuò)誤優(yōu)先的慣例奏属,所以回調(diào)函數(shù)的第一個(gè)參數(shù)為錯(cuò)誤信息,如果有的話潮峦。如果操作會(huì)返回結(jié)果囱皿,他將被作為第二個(gè)參數(shù)。
你也可以使用create()方法忱嘹,在你定義對(duì)象的同時(shí)保存他嘱腥。回調(diào)函數(shù)將返回錯(cuò)誤信息作為第一個(gè)參數(shù)拘悦,創(chuàng)建的實(shí)體作為第二個(gè)參數(shù)齿兔。
SomeModel.create({ name: 'also_awesome' }, function (err, awesome_instance) {
if (err) return handleError(err);
// saved!
});
每一個(gè)Model都有一個(gè)相關(guān)的連接對(duì)象(當(dāng)你使用model()方法時(shí),會(huì)使用默認(rèn)方法)础米,你可以創(chuàng)建一個(gè)新的連接分苇,并調(diào)用他的model()方法,用以在不同的數(shù)據(jù)庫(kù)中創(chuàng)建記錄椭盏。
你可以使用點(diǎn)語(yǔ)法去訪問(wèn)對(duì)象屬性组砚,更改屬性值。你必須使用save()或update()將變更保存到數(shù)據(jù)庫(kù)中掏颊。
// Access model field values using dot notation
console.log(awesome_instance.name); //should log 'also_awesome'
// Change record by modifying the fields, then calling save().
awesome_instance.name="New cool name";
awesome_instance.save(function (err) {
if (err) return handleError(err); // saved!
});
搜索數(shù)據(jù)
你可以通過(guò)查詢(xún)方法去檢索數(shù)據(jù)記錄糟红,并用JSON對(duì)象來(lái)指定查詢(xún)條件艾帐。下面的代碼展示了如何查詢(xún)所有參加網(wǎng)球運(yùn)動(dòng)的運(yùn)動(dòng)員,并只返回姓名和年齡盆偿。這里我們只匹配了運(yùn)動(dòng)這一個(gè)屬性柒爸,但是你們可以指定更多的檢索條件,如一個(gè)正則表達(dá)式事扭,或者不要任何條件捎稚,返回所有數(shù)據(jù)。
var Athlete = mongoose.model('Athlete', yourSchema);
// find all athletes who play tennis, selecting the 'name' and 'age' fields
Athlete.find({ 'sport': 'Tennis' }, 'name age', function (err, athletes) {
if (err) return handleError(err);
// 'athletes' contains the list of athletes that match the criteria.
})
如果你向上面一樣指定了回調(diào)方法求橄,查詢(xún)會(huì)馬上執(zhí)行今野,而回調(diào)方法會(huì)在查詢(xún)完成后執(zhí)行。
在mongoose中所有回調(diào)函數(shù)都采用了callback(error, result)的形式罐农。如果在查詢(xún)時(shí)發(fā)生錯(cuò)誤条霜,error中將包含錯(cuò)誤信息,而result將返回null涵亏。如果查詢(xún)成功error是null宰睡,而result中包含查詢(xún)的結(jié)果。
如果你沒(méi)有傳遞回調(diào)方法气筋,程序?qū)⒎祷匾粋€(gè)Query對(duì)象拆内。你可以使用這個(gè)query對(duì)象去組建你的查詢(xún),之后調(diào)用exec()方法執(zhí)行他宠默,并傳入回調(diào)方法麸恍。
// find all athletes that play tennis
var query = Athlete.find({ 'sport': 'Tennis' });
// selecting the 'name' and 'age' fields
query.select('name age');
// limit our results to 5 items
query.limit(5);
// sort by age
query.sort({ age: -1 });
// execute the query at a later time
query.exec(function (err, athletes) {
if (err) return handleError(err);
// athletes contains an ordered list of 5 athletes who play Tennis
})
上面的代碼中,我們?cè)趂ind中指定了查詢(xún)條件搀矫。我們也可以使用where()方法或南,他能夠使用(.)點(diǎn)語(yǔ)法將所有查詢(xún)條件連接起來(lái),而不用分別指定艾君。下面的代碼等同于上面的代碼采够,但是我們添加了一個(gè)age查詢(xún)條件。
Athlete.
find().
where('sport').equals('Tennis').
where('age').gt(17).lt(50). //Additional where query
limit(5).
sort({ age: -1 }).
select('name age').
exec(callback); // where callback is the name of our callback function.
find()方法會(huì)查詢(xún)所有匹配的記錄冰垄,但是通常我們只需要其中的一條蹬癌。下面的方法用以查詢(xún)一條記錄:
- findById():通過(guò)id查詢(xún)
- findOne():依照一定的條件查詢(xún)一條記錄。
- findByIdAndRemove(), findByIdAndUpdate(), findOneAndRemove(), findOneAndUpdate(): (這個(gè)自己看名字也知道了虹茶,我就不翻了)
提示:也有count()方法逝薪,獲取指定條件的記錄數(shù)。常常用于蝴罪,你只想要知道數(shù)目而不是實(shí)際的記錄時(shí)董济。
查詢(xún)中你還可以作很多,詳情請(qǐng)看:Queries要门。
處理相關(guān)的對(duì)象 -----熱門(mén)
你可以使用ObjectId 屬性類(lèi)型創(chuàng)建一個(gè)索引連接兩個(gè)對(duì)象虏肾,或者使用ObjectId 的數(shù)組去連接多個(gè)對(duì)象廓啊。這個(gè)屬性存儲(chǔ)著model的id。如果你需要關(guān)聯(lián)對(duì)象的實(shí)際內(nèi)容封豪,你可以使用populate()方法去查詢(xún)并替換id為真實(shí)數(shù)據(jù)谴轮。
例如,一下的schema定義了作者和故事吹埠。每個(gè)作者有多個(gè)故事第步,我們將使用ObjectId 數(shù)組來(lái)表示他們。一個(gè)故事只有一個(gè)作者缘琅。"ref"屬性(高亮加粗顯示的粘都,makedown)告訴schema 連接哪個(gè)model。
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var authorSchema = Schema({
name : String,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
author : { type: Schema.Types.ObjectId, ref: 'Author' },
title : String,
});
var Story = mongoose.model('Story', storySchema);
var Author = mongoose.model('Author', authorSchema);
我們可以使用_id值去保存關(guān)聯(lián)對(duì)象的索引刷袍。下面我們創(chuàng)建一個(gè)author驯杜,之后是一個(gè)book對(duì)象,并關(guān)聯(lián)author對(duì)象到author屬性做个。
var bob = new Author({ name: 'Bob Smith' });
bob.save(function (err) {
if (err) return handleError(err);
//Bob now exists, so lets create a story
var story = new Story({
title: "Bob goes sledding",
author: bob._id // assign the _id from the our author Bob. This ID is created by default!
});
story.save(function (err) {
if (err) return handleError(err);
// Bob now has his story
});
});
我們的story對(duì)象依靠id獲得了author的索引。為了獲得詳細(xì)的author信息我們使用populate()方法滚局。如下:
Story
.findOne({ title: 'Bob goes sledding' })
.populate('author') //This populates the author id with actual author information!
.exec(function (err, story) {
if (err) return handleError(err);
console.log('The author is %s', story.author.name);
// prints "The author is Bob Smith"
});