MongoDB 和 Mongoose
MongoDB 是一个用来存储应用数据的数据库。Mongo 是一个非关系,“NoSQL” 的数据库。也就是说 Mongo 在一个记录里存储所有的数据,而不是像关系数据库那样存储在多个预设的表中。这种存储结构有很多好处:
- 可扩展:一般来讲,非关系型数据库可以分布式存储在不同的操作系统间。这意味着它可以以低成本方便的提高性能。
- 灵活:新的数据集和属性可以直接添加进文档而无需更改表。
- 可复制:可以并行拷贝数据,如果数据损坏了,备份也可以成为主数据源。
Mongo 支持 JSON 形式的指令查询,所以它是学习 JavaScript 后端的不二选择。因为通过它访问文档或者属性可以像访问 JavaScript 的对象一样方便。
Install and Set Up Mongoose
在 package.json 文件中添加 MongoDB 和 Mongoose 依赖,将 mLab 数据库的 URI 作为 MONGO_URI 变量存储在私有 .env 文件中。然后require('mongoose')
,使用mongoose.connect()
命令来连接数据库。
// 第一种方式
var mongoose = require("mongoose");
var mongodb = require("mongodb");
mongoose.connect(process.env.MONGO_URI);
// 第二种方式
var mongoose = require("mongoose");
var mongodb = require("mongodb");
var MongoClient = require('mongodb').MongoClient;
var client = new MongoClient(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true });
client.connect(function(err){
var collection = client.db("test").collection("devices");
// perform actions on te collection object
client.close();
})
Create a Model
我们需要一个 Schema,每一个 Schema 对应一个 MongoDB collection,并且在那个 collection 里面定义 documents 的模型。
Schemas 是 Models 的构建块。它们可以嵌套来创建复杂的模型。
Model 可以被实例化,实例化后的对象称为 documents。
创建一个拥有以下 Prototype 的 Person 对象:
- Person Prototype -
name : string [required]
age : number
favoriteFoods : array of strings (*)
你可以使用基础的 SchemaTypes 去添加更多的字段,比如使用 required 或者 unique 这样的简单验证去设置默认值。参考 Mongoose 文档。
注意: Glitch 是一个真实的服务,并且通过 handler 函数和 db 进行交互。 这些函数通过一些事件去触发(例如:有人从终端调用了你的 API),我们在这些练习中遵循同样的方法。 比如,我们在完成 nserting、searching、updating 或者 deleting 这样的异步操作后接着回调done()
函数。它遵循 Node 的惯例,需要在 success 时回调done(null, data)
,在 error 时回调done(err)
。
Warning - 当与远程服务器交互时可能发生错误!
/* 示例 */
var someFunc = function(done) {
// 执行一些可能产生错误的代码
if(error) return done(error);
done(null, result);
};
Create and Save a Record of a Model
使用 Person 的 constructor(构造器)函数可以创建一个 document 对象,该对象包含name
、age
和favoriteFoods
字段。这些字段的类型必须符合 Person Schema 里面定义的类型。然后调用document.save()
。使用 Node 惯例传递 callback。通常情况下,所有的 CRUD(增查改删)方法都会像下面一样作为最后一个参数去执行一个callback()
。
/* 示例 */
person.save(function(err, data) {
// 你的代码
});
var tiffany = new Person({name: "tiffany", age: 28, favoriteFoods: ["apple", "raspberry", "banana"]});
tiffany.save(function(err, tiffany){
if(err) {
return console.error(err);
}
console.log(tiffany);
});
Create Many Records with model.create()
有时你需要创建很多的 model 实例。例如:在使用初始数据为数据库初始化时,Model.create()
接受一组像[{name:'John', ...}, {...}, ...]
的数组作为第一个参数,并将其保存到数据库。使用arrayOfPeople
作为Model.create()
的参数创建很多个 people 实例。
var arrayOfPeople = [{ name: 'jelly bean' }, { name: 'snickers' }];
Person.create(arrayOfPeople, function(err, persons){
if(err){
return console.error(err);
}
var jellybean = persons[0];
var snickers = persons[1];
})
Use model.find() to Search Your Database
使用Model.find() -> [Person]
来查询给定名称的所有的人。最简单的用法:Model.find()
接受一个查询的 document(一个 JSON 对象)作为第一参数,然后是回调。它将返回匹配到的项目组成的数组。这个支持极其广泛的搜索选项。使用人名作为搜索的关键词,来校验它。
Person.find({name: 'jelly bean'}, function (err, docs) {
if(err){
return console.error(err);
}
});
Use model.findOne() to Return a Single Matching Document from Your Database
Model.findOne()
表现像Model.find()
,但是它仅仅返回一个 document(而不是一个数组),即使数据库里有很多条 item(项目)。当你按声明成unique
的属性进行搜索时,Model.findOne()
尤其有用。
Person.findOne({avoriteFoods: ["apple"]}, function (err, adventure) {
if(err){
return console.error(err);
}
});
Use model.findById() to Search Your Database By _id
当我们保存一个 document, MongoDB 自动添加 _id 字段,并给该字段设置 unique(唯一)属性。通过 _id 搜索是一个非常频繁的操作,所以 Mongose 为它提供了一个专门的方法。
Person.findById('123', function (err, doc) {
if (err) return console.error(err);
// doc.name = 'jason bourne';
// doc.save(callback);
});
Perform Classic Updates by Running Find, Edit, then Save
传统应用里,如果你想要编辑 document,然后在某处使用它。你就必须在服务器响应中将其返回。Mongoose 有一个专用的更新方法:Model.update() , 它与低级的 mongo 驱动绑定,可以批量编辑符合特定条件的多个 document,而不用返回更新后的 document,取而代之返回'状态'消息。此外,它使模型校验变得更棘手,因为它是直接调用了 mongo 的驱动程序。
Person.update({ name: 'Tobi' }, { ferret: true }, { multi: true }, function (err, raw) {
if (err) return console.log(err);
console.log('The raw response from Mongo was ', raw);
});
Perform New Updates on a Document Using model.findOneAndUpdate()
mongoose 的最新版本简化了 documents 的更新。 但是一些高级的用法 (比如 pre/post 钩子, 验证) 更复杂, 所以老方法更常用。当通过 Id 进行搜索时还可以使用 findByIdAndUpdate()
。
A.findByIdAndUpdate(id, update, options, callback) // executes
A.findByIdAndUpdate(id, update, options) // returns Query
A.findByIdAndUpdate(id, update, callback) // executes
A.findByIdAndUpdate(id, update) // returns Query
A.findByIdAndUpdate()
Person.findByIdAndUpdate('213', { $set: { name: 'jason bourne' }}, function (err, doc) {
if (err) return console.error(err);
// doc.name = 'jason bourne';
// doc.save(callback);
})
Delete One Document Using model.findByIdAndRemove
使用 findByIdAndRemove()
或者 findOneAndRemove()
方法, 通过 _id 删除一个人员。
A.findByIdAndRemove(id, options, callback) // executes
A.findByIdAndRemove(id, options) // return Query
A.findByIdAndRemove(id, callback) // executes
A.findByIdAndRemove(id) // returns Query
A.findByIdAndRemove() // returns Query
Person.findByIdAndRemove('245', function (err, doc) {
if (err) return console.error(err);
// doc.name = 'jason bourne';
// doc.save(callback);
})
Delete Many Documents with model.remove()
Model.remove()
可用于删除与给定条件匹配的所有 document。 如果想要删除所有叫 “Mary” 的人, 可以使用 Model.remove()
。
var conditions = { name: 'tom' };
Person.remove(conditions, function(error){
if(error) {
console.log(error);
} else {
console.log('Delete success!');
}
});
Chain Search Query Helpers to Narrow Search Results
如果不给 Model.find()
(或者别的搜索方法)传递回调函数,作为的最后一个参数, 则不执行查询。你可以将查询存储在变量中供以后使用,这类对象可以使用链接语法构建查询。 当你最终链接 .exec()
方法时,将执行实际的数据库操作。最后将回调传递给 exec()
方法。 有很多的查询助手, 这里我们使用最 '著名' 的一种。
Model.find({},null,{sort:{age:-1}},function(err,docs){
//查询所有数据,并按照age降序顺序返回数据docs
});
Model.find({},null,{limit:20},function(err,docs){
console.log(docs);
});
query.sort('field -test');
query.limit(20)
T.find().select('-x').exec(callback);
ps: 这篇文章很多不全的,有时间再扩展。