0
点赞
收藏
分享

微信扫一扫

MongoDB & Mongoose

灵魂跑者 2022-10-02 阅读 213

MongoDB 和 Mongoose

mongoose

建立一个 MongoDB Atlas 数据库并导入连接到它所需的软件包。将 ​​mongodb@~3.6.0​​ 和 ​​mongoose@~5.4.0​​ 添加到项目的 ​​package.json​​ 中。 然后,在 ​​myApp.js​​ 文件中请求 ​​mongoose​​。 创建一个 ​​.env​​ 文件,给它添加一个 ​​MONGO_URI​​ 变量。 变量的值为 MongoDB Atlas 数据库 URI。 应用单引号或双引号包裹 URI。请记住,环境变量 ​​=​​ 两边不能有空格。 例如应该这样写:​​MONGO_URI='VALUE'​​。 完成后,使用下面的代码来连接数据库。

mongoose.connect(<Your URI>, { useNewUrlParser: true, useUnifiedTopology: true });

const mongoose = require('mongoose');
mongoose.connect("mongodb+srv://<username>:<password>@cluster0.zbwns.mongodb.net/myFirstDatabase?retryWrites=true&w=majority", { useNewUrlParser: true, useUnifiedTopology: true });

创建模型 Model

C RUD 第一小节——CREATE

首先,需要一个 Schema, 每一个 Schema 都对应一个 MongoDB 的 collection, 并且在相应的 collection 里定义 documents 的“样子”。 Schema 用于组成模型(Model), 可以通过嵌套 Schema 来创建复杂的模型。可以根据模型创建实例,模型实例化后的对象称为 documents。

handler 函数会在特定事件(比如调用服务器 API)发生时执行。 ​​done()​​ 是一个回调函数,它的作用是在一个异步操作(比如对数据库进行插入、查询、更新或删除)执行完成时,告知可以继续执行后续的其它代码。 这与 Node.js 中的处理方式十分类似,在 Node.js 中,在(异步操作)成功时调用 ​​done(null, data)​​,在失败时调用 ​​done(err)​​。

注意:与远程服务器进行交互时,需要考虑到发生错误的可能!

/* Example */
const someFunc = function(done) {
//... do something (risky) ...
if (error) return done(error);
done(null, result);
};

按下面的原型信息创建一个名为 ​​personSchema​​ 的 schema:

- Person Prototype -
--------------------
name : string [required]
age : number
favoriteFoods : array of strings (*)

采用 Mongoose 基础 schema 类型。 如果还想添加更多的键,就请使用 required 或 unique 等简单的验证器(validators),并设置默认值。 详情请参考 ​​Mongoose 文档​​。

请从 ​​personSchema​​ 创建一个名为 ​​Person​​ 的 model。

const Schema = mongoose.Schema;
const personSchema = new Schema({
name: { type: String, required: true },
age: Number,
favoriteFoods: [String]
});
const Person = mongoose.model("Person", personSchema);

创建并保存一条 Model 记录

在 ​​createAndSavePerson​​ 函数中,使用在上一个挑战中写好的 ​​Person​​ 构造函数创建 document 实例, 将包含 ​​name​​、​​age​​ 和 ​​favoriteFoods​​ 的对象传给构造函数, 这些属性的数据类型必须符合在 ​​personSchema​​ 中定义的类型。 然后在返回的 document 实例上调用方法 ​​document.save()​​。 同时,按 Node.js 的方式为它传一个回调函数。 这是一种常见模式,以下所有 CRUD 方法都将这样的回调函数作为最后一个参数。

/* Example */
// ...
person.save(function(err, data) {
// ...do your stuff here...
});

let createAndSavePerson = function(done) {
let janeFonda = new Person({name: "Jane Fonda", age: 84, favoriteFoods: ["eggs", "fish", "fresh fruit"]});

janeFonda.save(function(err, data) {
if (err) return console.error(err);
done(null, data)
});
};

model.create() 创建多条记录

在一些情况下,比如进行数据库初始化,会需要创建很多 model 实例来用作初始数据。 ​​Model.create()​​ 接受一组像 ​​[{name: 'John', ...}, {...}, ...]​​ 的数组作为第一个参数,并将其保存到数据库。

let arrayOfPeople = [
{name: "Frankie", age: 74, favoriteFoods: ["Del Taco"]},
{name: "Sol", age: 76, favoriteFoods: ["roast chicken"]},
{name: "Robert", age: 78, favoriteFoods: ["wine"]}
];

let createManyPeople = function(arrayOfPeople, done) {
Person.create(arrayOfPeople, function (err, people) {
if (err) return console.log(err);
done(null, people);
});
};

model.find() 查询数据库

C R UD 第二小节—— Read 查询

尝试一种最简单的用法,​​Model.find()​​ 接收一个查询 document(一个 JSON 对象)作为第一个参数,一个回调函数作为第二个参数, 它会返回由匹配到的数据组成的数组。 这个方法支持很多搜索选项, 详情请参阅文档。

let findPeopleByName = function(personName, done) {
Person.find({name: personName}, function (err, personFound) {
if (err) return console.log(err);
done(null, personFound);
});
};

model.findOne() 返回一个单一匹配

​Model.findOne()​​ 与 ​​Model.find()​​ 十分类似,但就算数据库中有很多条数据可以匹配查询条件,它也只返回一个 document,而不会返回一个数组, 如果查询条件是声明为唯一值的属性,它会更加适用。

let findOneByFood = function(food, done) {
Person.findOne({favoriteFoods: food}, function (err, data) {
if (err) return console.log(err);
done(null, data);
});
};

model.findById() 根据 _id 搜索

在保存 document 的时候,MongoDB 会自动为它添加 ​​_id​​ 字段,并给该字段设置一个唯一的仅包含数字和字母的值。 通过 ​​_id​​ 搜索是一个十分常见的操作,为此,Mongoose 提供了一个专门的方法。

var findPersonById = function(personId, done) {
Person.findById(personId, function (err, data) {
if (err) return console.log(err);
done(null, data);
});
};

通过执行查询、编辑、保存来执行经典更新流程

CR U D 第三小节—— Update 更新

在过去,如果想要编辑 document 并以某种方式使用它(比如放到服务器的返回数据中),就必须执行查找、编辑和保存。 Mongoose 有一个专用的更新方法 ​​Model.update()​​, 它与底层的 mongo 驱动绑定。 通过这个方法,可以批量编辑符合特定条件的多个 document。但问题在于,这个方法不会返回更新后的 document,而是返回状态信息。 此外,它直接调用 mongo 的底层驱动,让处理 model 的验证变得更加棘手。

const findEditThenSave = (personId, done) => {
const foodToAdd = 'hamburger';
Person.findById(personId, (err, person) => {
if(err) return console.log(err); person.favoriteFoods.push(foodToAdd);
person.save((err, updatedPerson) => {
if(err) return console.log(err);
done(null, updatedPerson)
})
})
};

在 document 中执行新的更新方式——使用 model.findOneAndUpdate()

最近发布的 mongoose 版本简化了 document 的更新方式, 但同时,一些高级功能(如 pre/post hook, 验证)的使用方式也变得和以前不同。因此,在很多情景下,上一个挑战中提到的老方法其实更常用。 新方法的加入,可以让我们使用 ​​findByIdAndUpdate()​​ 来进行基于 id 的搜索。

const findAndUpdate = (personName, done) => {
const ageToSet = 20;

Person.findOneAndUpdate({name: personName}, {age: ageToSet}, {new: true}, (err, updatedDoc) => {
if(err) return console.log(err);
done(null, updatedDoc);
})
};

提示: 需要返回更新后的 document。 可以把 ​​findOneAndUpdate()​​ 的第三个参数设置为 ​​{ new: true }​​ 。 默认情况下,这个方法会返回修改前的数据。

model.findByIdAndRemove 删除一个 document

CRU D 第四小节—— Delete 删除

​findByIdAndRemove​​ 和 ​​findOneAndRemove​​ 类似于之前的更新方法, 它们将被删除的 document 传给数据库。 和之前一样,使用函数参数 ​​personId​​ 作为查询关键字。

修改 ​​removeById​​ 函数,通过 ​​_id​​ 删除一个人的数据, 可以使用 ​​findByIdAndRemove()​​ 或 ​​findOneAndRemove()​​ 方法。

let removeById = function(personId, done) {
Person.findByIdAndRemove(
personId,
(err, removedDoc) => {
if(err) return console.log(err);
done(null, removedDoc);
}
);
};

model.remove() 删除多个 document

​Model.remove()​​ 可以用于删除符合给定匹配条件的所有 document。

修改 ​​removeManyPeople​​ 函数,使用 ​​nameToRemove​​ 删除所有姓名是变量 ​​Model.remove()​​ 的人。 给它传入一个带有 ​​name​​ 字段的查询 document 和一个回调函数。

注意:​Model.remove()​​ 不会返回被删除的 document,而是会返回一个包含操作结果以及受影响的数据数量的 JSON 对象。 不要忘记将它传入 ​​done()​​ 回调函数,因为我们需要在挑战的测试中调用它。

const removeManyPeople = (done) => {
const nameToRemove = "Mary";
Person.remove({name: nameToRemove}, (err, response) => {
if(err) return console.log(err);
done(null, response);
})
};

链式调用辅助查询函数来缩小搜索结果

如果不给 ​​Model.find()​​(或者别的搜索方法)的最后一个参数传入回调函数, 查询将不会执行。 可以将查询条件存储在变量中供以后使用, 也可以通过链式调用这类变量来构建新的查询字段。 实际的数据库操作会在最后调用 ​​.exec()​​ 方法时执行。 必须把回调函数传给最后一个方法。 Mongoose 提供了许多辅助查询函数, 这里使用最常见的一种。

修改 ​​queryChain​​ 函数来查询喜欢 ​​foodToSearch​​ 食物的人。 同时,需要将查询结果按 ​​name​​ 属性排序, 查询结果应限制在两个 document 内,并隐藏 age 属性。 请链式调用 ​​.find()​​、​​.sort()​​、​​.limit()​​ 和 ​​.select()​​,并在最后调用 ​​.exec()​​, 并将 ​​done(err, data)​​ 回调函数传入 ​​exec()​​。

let queryChain = function(done) {
var foodToSearch = "burrito";
var jsonObject = {favoriteFoods : foodToSearch};
Person.find(jsonObject).sort({name: 1}).limit(2).select({age: 0}).exec((err, data) => {
(err) ? done(err) : done(null, data);
})
};

举报

相关推荐

0 条评论