细嚼慢咽 Mongoose 5

此文已由做者黄锴受权网易云社区发布。
html

欢迎访问网易云社区,了解更多网易技术产品运营经验。前端

前言

因为Mongoose一直没有中文文档,加上如今市面上充斥着太多“快速上手”,不少中文文档都只盲目介绍了Mongoose的API用法(可是如今升级后,不少API发生了变化),没有作详细介绍,致使不少人用了半天的Mongoose,仍是对其只知其一;不知其二(好比我!),所以写了这篇文章,从如下三个角度聊聊Mongoose。web

  • 是什么(what?)mongodb

  • 为何?(why?)数据库

  • 怎么用(how?)编程

    • 快速上手api

    • 再深一点(这才是细嚼慢咽的关键哦)数组

本文阅读可快,可慢全凭喜爱。但本着贪多嚼不烂的想法,仍是但愿客观慢慢品尝。promise

是什么(what)?


首先,必需要知道Mongoose是什么缓存

Mongoose(狐獴)就是图上这个小可爱。(学名:Suricata suricatta),头尾长42-60厘米,是一种小型的哺乳动物……

好像有点跑题。固然,今天介绍的Mongoose不是真的小动物,而是一款在Node.js环境下对MongoDB API 进行便捷操做的对象模型工具(因此理论上,我默认你是须要大概懂MongoDB数据库才会来用这个的)。

要特别强调的是,我这里说它是对象模型工具,说明Mongoose的操做是以对象为单位的。

同时,因为Mongoose升级后(差很少)全面支持Promise,能够很方便的对接async/await语法。所以接下来的个人代码都会默认使用Promise形式。

为何(Why)?

咱们知道,MongoDB官网提供了一个Node.js环境下的MongoAPI,那为何我还须要使用Mongoose呢?固然是由于它提供了一些官方不能提供的功能,如它官网介绍的:

Let's face it, writing MongoDB validation, casting and business logic boilerplate is a drag.

能够看出,Mongoose主要是减轻咱们在写数据验证,业务逻辑模板的负担。同时,因为Mongoose一直强调它是一个MongoDB对象建模工具,所以在这里就必需要提出Mongoose的核心,也是Mongoose困扰人已久的一个东西——模式和模型。

模式?模型?

对于Mongoose的新人来讲,最头疼的就是它里面有关模式(Schema),模型(Model)的概念。Mongoose的一切都始于一个模式。这点和MongoDB基于集合(Collection)的思路可能不太一致,由于自己MongoDB是无模式的,也正是由于它的无模型,致使其使用起来极具灵活性。

那Mongoose为何要定义一个模型?Why Define a Mongoose Schema? 给出了解释:

have you ever wondered how to pull these random documents out and figure out which properties were saved to document? The truth is that for 90% of your web applications you’ll be using model classes and you’ll have a standard set of fields you’ll be expecting to be saved to your database

模式有模式的好处,生活中绝大部分的数据是遵循必定的模式的,模式能让咱们规范数据的表现形式,不至于太为所欲为。同时模式给咱们提供了不少数据验证的便利(这就像咱们讨论JavaScript弱类型和TypeScript强类型是同样同样的)。

同时,因为Mongoose使用的依然MongoDB而非关系型数据库,所以它没有彻底失去其天生的灵活性,它依然开放了让你能够定义任意字段的能力。

// Defining a schema on a Mongoose model// that allows storage of arbitrary fields// Mongoose.schema(schemaObject, options)var User = Mongoose.schema({
  username: String,
  password: String}, {
  strict: false});复制代码

注意到上面代码的第二个字段,你把strict设置为false,你就能在这个模型中加入任意字段了(可是仍是不建议这样作,由于这意味着你须要本身去作数据的验证)。

若是你实在不习惯使用 模式,可使用MongoDB官方的API。

与其说Mongoose定义模式是画蛇添足的,不如说,它在灵活性的基础上,提供了更安全的模型化操做对象的方式。

我我的感受:使用Mongoose你更有操做对象的感受。

模式 VS 模型

咱们已经知道了模式是有其优点的,那为何我还须要模型?这两个有什么区别?

官方的定义:Each schema defines the shape of the documents within that collection.

模式

模式它是一个 抽象的概念。其实能够把模式考虑成设计规范 ,定义了设计图纸应该如何画,默认单位是多少,若是没有该规范,那每一个人画的设计图纸就是各式各样,无法真正投入建造。


模型

模型相对于模式是具体的概念,能够把模型考虑成设计图纸 :按照设计规范画出一个图纸,任何人根据该规范就能够把房子造出来。

实例

而模型的实例才是真正的咱们住的房子,在MongoDB里也就是文档(document)


画蛇添足?

你可能会说,何须画蛇添足,把模式和模型合起来不就行了嘛?不少人喜欢这样写:

const studentModel = Mongoose.model('Student', new Mongoose.Schema({ name: String, sex: String});复制代码

这样写也能够,可是这个前提是你肯定你的模式只在这一个模型中使用。之因此有个模式这个抽象概念,就像设计规范, 它历来不是说只能在一张图纸中使用,你能够利用这个规范绘制出不少符合规范的图纸。

有时候你可能会有这样的需求,基本同样的数据结构,可是我须要建多个不一样集合,或者稍微修改一下模式,新建一个新的集合,这时候把模式独立出来,你就会发现省事不少了。

const personSchema = new Mongoose.Schema({ name: String, sex: String});const studentModel = Mongoose.model('Student', personSchema);const otherStudentModel = Mongoose.model('OtherStudent', personSchema);const teacherSchema = personSchema.clone();
teacherSchema.add({ teach: String});const teacherModel = Mongoose.model('Teacher', teacherSchema);复制代码

举例

再来举一个例子:假设,咱们创建了一个宠物猫咪乐园,咱们须要去招集一批宠物喵成为咱们的会员。可是呢,咱们的宣传员他没见过喵(多么神奇的生物)。因而,咱们绞尽脑汁,合计出一个规范:全部的宠物猫应该知足三个属性name,type, meow。也就是说,宠物喵必需要有名字,必须有一个品种,同时它必需要会“喵喵”叫!

const catSchema = new Mongoose.Schema({ name: String, type: String,meow: Boolean});复制代码

好了,如今咱们把规范告诉他,可是他说他记性很差。怕忘记,所以咱们制定了一个叫《宠物猫咪指南1.0》的手册

const CatGuide = Mongoose.model('Animal', catSchema);复制代码

好了,宣传员开心的出去了,开始处处撩猫去了,把全部它认为是猫的生物都记录下来:

const kitty1 = new CatGuide({ name: 'mimi', type: 'American Shorthair', meow: true });const kitty2 = new CatGuide({ name: 'kaddy', type: 'American Shorthair', meow: true });const doggy = new CatGuide({ name: 'doggy', type: 'Dog!!', meow: false });
……复制代码

(可是这个不靠谱的,拿着手册也能找错,找了一只穿猫咪衣服的狗!!?)


所以,咱们只把那两只猫保存到数据库里。

kitty1.save().then(() => console.log('meow'));
kitty2.save().then(() => console.log('meow'));复制代码

知道了他们之间的关系,剩下的就好办了。就是编程了,编程能解决的事情都是简单的事情。

怎么用(How)?

快速开始

Mongoose的使用流程很简单:

链接 ——> 定义模式 ——> 生成Model ——> 生成Model实例复制代码

其中,链接,Model,实例是实际跟数据库打交道的,他们之间的关系以下:

经过一个很简单的例子,咱们就能够上手操做MongoDB,而后配合官方API,熟练的人能够直接跳过了,可是若是你想了解更多细节,能够继续看下去,看看每一个操做具体还能够怎么配置。

// step 1 引入Mongooseconst Mongoose = require('Mongoose');// setp2 创建链接Mongoose.connect('MongoDB://localhost/test');// step3 创建模式const catSchema = new Mongoose.Schema({ name: String, type: String });// step4 生成模型const Cat = Mongoose.model('Cat', catSchema);// step5.1 模型直接操做documentCat.create({ name: 'mimi', type: 'American Shorthair' }).then(...)// or
                                                              // step5.2 生成实例,操做documentconst kitty = new Cat({ name: 'mimi', type: 'American Shorthair' });
kitty.save().then(() => console.log('meow'));复制代码

链接

咱们都知道,使用数据库的第一步是须要连上数据库,Mongoose提供了一个很简单的方式链接:connect。

Mongoose.connect(url, [options]);复制代码

注意,如今使用url须要加上 { useNewUrlParser: true }选项,不然可能会报错。 Mongoose.connect(url, { useNewUrlParser: true });

其中url参数的完整形式,跟MongoDB链接字符串的一致:MongoDB://username:password@host:port/database?options...

默认状况下,用户名和密码能够省略:

Mongoose.connect('MongoDB://localhost/db1');复制代码

若是还须要传递用户名、密码,则可使用以下方式

Mongoose.connect('MongoDB://username:password@host:port/database?options...');复制代码

connect()方法还接受一个选项对象options,该对象将传递给底层驱动程序。这里所包含的全部选项优先于链接字符串中传递的选项:

  • bufferCommands : 这个选项会关闭Mongoose的缓存机制 ,再深一点章节会说。

  • user/pass :用户名和密码

  • autoIndex :一般MongoDB会自动生成索引,可是有时候若是你不须要,能够把这个选项设置为false

  • dbName :制定数据库名,通常是没办法在链接字符串中指定的情形( MongoDB+srv 语法链接到 MongoDB Atlas

还有一些选项是用来配置Mongoose的,例如,我以前说的useNewUrlParser ,还有 pooleSize, bufferMaxEntries,connectTimeoutMS, socketTimeoutMS…… 这些都是比较高级的配置,通常人用不到。若是真的须要用到,能够翻官方文档

模式

咱们知道,模式其的是规范的做用,所以定义模式主要是定义咱们数据的表现形式以及作一些格式约定,方便自动校验。例如,我建立了一个学生的模式,它规定了name和age字段的类型:

const studentSchema = new Mongoose.Schema({
  name: String,
  age: Number,
});复制代码

基本类型

模式有如下10种基本类型,若是只使用基本类型,就输入如下字段就行

  • String | Number | Date | Buffer | Boolean | Schema.Types.Mixed | Schema.Types.ObjectId | Array | Schema.Types.Decimal128 | Map(新加入的ES6的Map)

注意:1. 若是是Array,可使用[]代替,你能够能够规定Array内部数据类型,例如数字数组: [Number]。2. 不少人困惑为何没有Object类型,若是你想定义对象,使用Schema.Types.Mixed就好了。Mixed类型支持多种类型混合,好比数组套对象,对象套数组……

额外约束

可是,只规定了基本类型还不够,我想作一些额外的约束,好比姓名长度,年龄大小。所以每种类型还有不少配置项,若是要使用额外的约束,须要使用Object形式,同时,类型经过type引入:

const studentSchema = new Mongoose.Schema({
  name: { type: String, minlength: 2 },
  age: { type: Number, min: 12, max: 16},
});复制代码

这里只介绍一些比较经常使用的,更多使用说明参考官方手册

全部类型可用:

  • required: boolean or function, 很好理解,若是为真就表示该字段必需要存在

  • default: Any or function, 设置默认值

  • validate: function, 增长一个校验函数

字符串 String:

  • lowercase/upppercase: boolean, 是否作大小写处理

  • trim: boolean, 是否去除首尾空格

  • match: RegExp, 只有知足特定正则的值才能被接受

  • enum: Array, 只有数组内的值才被接受

  • minlength/ maxLength: Number, 最小、大长度

数字 Number / 日期 Date

  • min / max: Number / Date (根据类型),必须知足的最大值/最小值

注意: Date使用的是内置的Date,可是你使用setMonth等内置的方法,不会被Mongoose不会识别到,所以使用doc.save()不会有效果。你必须设置doc.markModified(pathToYourDate)。

const Assignment = Mongoose.model('Assignment', { name: String, dueDate: Date });const a = new Assignment({ name: 'test', dueDate: Date.now() });
a.save().then(callback);
Assignment.findOne({ name: 'test' }, 'name dueDate', (err, doc) => {
doc.dueDate.setMonth(3);
doc.save(callback); // THIS DOES NOT SAVE YOUR CHANGEdoc.markModified('dueDate');
doc.save(callback); // works});复制代码

模型

有了模式以后,就能够生成模型了,生成模型很简单,就使用model函数就好了。

// step3 创建模式const catSchema = new Mongoose.Schema({ name: String, type: String });// step4 生成模型const Cat = Mongoose.model('Cat', catSchema);复制代码

注意,虽然全部的例子都是Mongoose.model,可是实际上model是Connect原型的方法:Connection.prototype.model(),即一个链接实例才有model方法。(具体的能够看后面的 再深一点章节)

其中,model第一个参数就是collection名称(Mongoose会自动 复数化,想修更名称也请看后面章节),同时model会把Schema里的内容复制一份

官方原文是说复制一份

The .model() function makes a copy of schema. Make sure that you've added everything you want to schema before calling .model()!

可是我实际测试,感受仍是引用,在调用model方法以后,经过add(), remove()方法修改Schema依然会影响以前建立的model。

const catSchema = new Mongoose.Schema({ name: String, type: String });const Cat = Mongoose.model('Cat', catSchema);
catSchema.remove('type');   // 在建立model后修改Schema会影响以前的modelconst kitty = new Cat({ name: 'mimi2', type: 'American Shorthair' });
kitty.save().then(() => console.log('meow'));  // type字段不会存储到数据库复制代码

实例

根据以前的图能够知道,model的实例就是文档,有一些比较方便的操做方法,更多方法参考文档

get(path,opt) : 获取文档的某个字段,这个函数比较好的是作数据处理,第2个参数能够将该字段转换成其余类型:«Schema|String|Number|Buffer|*»

doc.get('age') // 47

  // dynamic casting to a string
  doc.get('age', String) // "47"复制代码

save():顾名思义保存文档到数据库

var Tank = Mongoose.model('Tank', yourSchema);var small = new Tank({ size: 'small' });
small.save(function (err) {  if (err) return handleError(err);  // saved!});复制代码

set(path, value, opt) : 设置文档的某个字段,第三个参数依然能够修改字段类型,同时,能够设置{ strict: false }添加任意字段(回顾 为何章节)

// 简单用法doc.set(path, value)// 对象形式用法,修改多个字段doc.set({
    path  : value
  , path2 : {
       path  : value
    }
})// 把value经过Number进行转换doc.set(path, value, Number)// 填加任意字段doc.set(path, value, { strict: false });复制代码

CRUD操做

因为对文档的操做一般是在"集合"这个维度,所以大部分的操做都是在model上完成的,除了一些单文档的操做能够在文档这个维度,经过实例完成

新增文档[s]

文档保存有三种方法,除了以前介绍的save方法,还可使用模型的下面两种方法。

  • model.create(object) : 其实就是new model.save()的简写

  • model.insertMany([object]) : 能够批量增长,从内存写到数据库比较实用

区别就像实例的save是猫主人本身跑过来报名。create,insertMany就是咱们工做人员替用户直接录入。

const catSchema = new Mongoose.Schema({ name: String, type: String });const Cat = Mongoose.model('Cat', catSchema);
Cat.create({ name: 'mimi', type: 'American Shorthair' }).then(...)  // 插入单条文档Cat.insertMany([{ name: 'mimi', type: 'American Shorthair' }...]).then(...)  // 插入多条文档复制代码

查找文档

Mongoose的查删改的使用方法基本大同小异,这里重点介绍一下查询,剩下的更新和删除主要介绍方法,不会具体介绍怎么使用

跟查询有关的方法有…一堆(ByID那一批我排除了,实际用途不大,不少时候咱们都不知道文档的_id):

大部分都大同小意,而后findOne跟find的差异就是,一个是查询全部知足条件的文档,一个是只返回第一个,所以我这里只讲一个find的用法:

Modle.find.(conditions, [projection], [options], [callback] )复制代码
  • conditions «Object» : 查询条件(彻底跟MongoDB手册一致)

  • [projection] «Object|String» : 选取字段,和下面的select方法彻底一致(我推荐使用链式调用)

  • [options] «Object» : 查询配置(在再深一点章节再介绍)

  • [callback] «Function» : 推荐使用Promise写发,不写callback

通常来讲,查找MongoDB中的某个文档,是须要一个查询条件(condition)的,这个查询条件能够简单能够复杂,因为彻底跟MongoDB手册一致,本文毕竟不是《MongoDB入门》这里就不作过多叙述,若是后续有时间会把整理的MongoDB手册发上来, 下面的例子也会说明一些。

这里重点说一下Mongoose自身提供的一些比较使用的方法,这里举官方一个例子来讲明一下:

一般一个标准的MongoDB的查询大概是这样(其中Person是一个model),Mongoose彻底支持这种查询方式:

Person.
  find({    // 这里写查询条件
    occupation: /host/,   // 查询条件能够用正则
    'name.last': 'Ghost',   //  限定name.last 
    age: { $gt: 17, $lt: 66 },   // 限定年龄范围
    likes: { $in: ['vaporizing', 'talking'] }   // 限定喜爱必需要在这个数组中
  }).
  limit(10).    // 限定取出的文档条数
  sort({ occupation: -1 }).  // 针对某个字段排序,1表示正序,-1表示逆序
  select({ name: 1, occupation: 1 }).  // 选择取出的字段,1表示取出,0表示不取出,若是不须要id,须要显式写{_id : 0}
  exec(callback);  // 这里使用then也行,彻底支持Promise,可是查询不是Promise,这个要注意,后面会说复制代码

可是Mongoose把 经常使用的方法都提取出来了,例如:where,gt,lt,in……(完整API文档),所以更推荐使用下面这种方式:

// Using query builderPerson.
  find({ occupation: /host/ }).
  where('name.last').equals('Ghost').
  where('age').gt(17).lt(66).
  where('likes').in(['vaporizing', 'talking']).
  limit(10).
  sort('-occupation').
  select('name occupation').
  exec(callback);复制代码

要强调一下,查询支持promise一些语法,可是它不是promise。这个坑必需要记得!! 千万不要将callback形式和promise混用!

例如,下面的query能够执行三次!并不会由于一次then或者callback结束。 说明then只是一个执行方法,查询并非真正的Promise。

const q = MyModel.updateMany({}, { isDeleted: true }, function() {  console.log('Update 1');
});
q.then(() => console.log('Update 2'));
q.then(() => console.log('Update 3'));复制代码

若是要统计查询的文档数据,可使用countDocuments(),用法和MongoDB的count()一致

Person.find(...)
.count()
.then() // 这里得到的是一个数字复制代码

注意: Mongoose的count()已经被废弃,须要统计个数得用countDocuments

更新文档

更新文档的方法有下面三个,condition的使用方法和find的方法一彻底一致(包括where那些查询方法均可以使用),只是要注意, update只是更新字段(符合Schema),可是replace是彻底的用新doc来替换。

删除文档

删除文档主要是两个方法,使用方法彻底和查询一致。

再深一点

细品链接

缓存机制

根据上面的例子,你会发现一个奇怪的现象, 咱们并无判断链接是否成功就进行了操做?这是由于Mongoose内部缓存了函数调用。

Mongoose lets you start using your models immediately, without waiting for Mongoose to establish a connection to MongoDB

这很cool,很方便,咱们不用去关心链接成功再去增长文档,不然你必需要这样:

Mongoose
    .connect('MongoDB://localhost/test')
    .then(() => {        const catSchema = new Mongoose.Schema({ name: String, type: String });        const Cat = Mongoose.model('Cat', catSchema);        const kitty = new Cat({ name: 'mimi', type: 'American Shorthair' });
        kitty.save().then(() => console.log('meow'));
    })
    .catch(err => console.log(err));复制代码

可是这样会带来一个问题就是你若是不创建链接,进行操做也不会收到任何提示。

var MyModel = Mongoose.model('Test', new Schema({ name: String }));// Will just hang until Mongoose successfully connectsMyModel.findOne(function(error, result) { /* ... */ });

setTimeout(function() {
  Mongoose.connect('MongoDB://localhost:27017/myapp');
}, 60000);复制代码

因此必定要养成良好的喜欢,在作查询,删除等操做的时候,判断一下是否已经链接。判断链接可使用下面提的 connection对象的链接状态码

connection对象

说实话,刚开始使用Mongoose的时候我老是充满疑惑,一开始我认为Mongoose应该是一个类,它表明一次链接,经过new的方式能够建立一个数据库的链接。可是Mongoose不是,它直接经过connect方法就建立了一个链接,就能直接操做数据库上的集合,那说明这个Mongoose只是一个实例(的确也是)。那若是Mongoose只是一个实例,它就等于那一个链接吗?那为何Mongoose上面没有操做数据库的方法?并且我要如何建立多个链接呢?一个个问题在脑海中回荡,脑子里早已一团浆糊,因而,仍是回到了官方文档找答案。

其实,每次执行Mongoose.connect,实际就是建立了一个Connection对象(这个对象能够经过Mongoose.connection得到)这个对象才是真正对应的一个数据库的链接。所以,全部的数据库操做其实都是在connect对象中,例如:createCollection()dropCollection(), dropDatabase() ……

这个connection对象同时能够监听几个经常使用事件:connected,disconnected,error。

const connection = Mongoose.connection;
connection.on('connected', () => {  console.log('Mongoose connection open');
  connection.createCollection('test').then(() => console.log('add collection')),
});复制代码

链接状态码

为了方便查看对象的状态,connection也提供了一个readyState属性,能够方便判断当前链接状态,经过Mongoose.STATES能获取readyState的全部取值:

{ '0': 'disconnected',
  '1': 'connected',
  '2': 'connecting',
  '3': 'disconnecting',
  '99': 'uninitialized',
  disconnected: 0,
  connected: 1,
  connecting: 2,
  disconnecting: 3,
  uninitialized: 99 }复制代码

因此,理论上你能够这样判断链接是否创建

if (Mongoose.STATES[connection.readyState] === 'connected') ....复制代码

多个链接

同时,若是你想建立多个链接,你可使用Mongoose.createConnection()的方式建立一个新的链接,参数什么的和connect一致,剩下的操做一致。例如如下这个官方例子:

var Mongoose = require('Mongoose');var db = Mongoose.createConnection(..);
db.model('Venue', new Schema(..));var Ticket = db.model('Ticket', new Schema(..));var Venue = db.model('Venue');复制代码

细品模式

虚属性

虚属性(Virtuals)是Mongoose提供的一个颇有用的功能,它能够方便咱们存储一些不须要存储在数据库中的数据。例如,我存储一个用户的姓名,只须要存名和姓:

const personSchema = new Schema({
    name: {
      first: String,
      last: String
    }
  });  const Person = Mongoose.model('Person', personSchema);  const voidsky = new Person({
    name: { first: 'void', last: 'sky' }
  });复制代码

可是我在读出的时候,须要打印用户的全名,固然咱们能够这样作:

console.log(voidsky.name.first + ' ' + voidsky.name.last); // void sky复制代码

可是虚属性提供了一个更方便的方式:

personSchema.virtual('fullName').get(function () {  return this.name.first + ' ' + this.name.last;
});console.log(voidsky.fullName);复制代码

若是你用过一些前端框架,你能够把它看成计算属性。可是这个属性不会被持久化到MongoDB中,虚函数有get和set的方法,熟悉setter和getter的就应该知道,同样同样的。

虚属性还提供了一个颇有用的Aliases字段,它能够把Schema的某个属性彻底跟一个虚属性进行链接(set和get的绑定),你操做这两个属性的效果彻底一致,这个好处是你能够在存储的时候节约空间,可是获取数据的时候,使用语义化的描述 。只是Aliases定义的属性不会被持久化到数据库。这里看官方案例:

const personSchema = new Schema({
  n: {
    type: String,
    alias: 'name'   // 注意这里,等于建立了一个name的虚属性,绑定到n
  }
});const Person = Mongoose.model(personSchema);const person = new Person({ name: 'Val' });console.log(person); // { n: 'Val' }console.log(person.toObject({ virtuals: true })); // { n: 'Val', name: 'Val' }console.log(person.name); // "Val"person.name = 'Not Val';console.log(person); // { n: 'Not Val' }复制代码

子模式

schema是能够嵌套的,若是咱们须要定义一个复杂的结构,可使用嵌套的方式(一般子模式会配置成{ _id: false },具体能够参考下面的模式配置)

const childSchema = new Schema({
  n: {
    type: String,
    alias: 'name'
  }
}, { _id: false });const parentSchema = new Schema({  // If in a child schema, alias doesn't need to include the full nested path c: childSchema, name: { f: { type: String, // Alias needs to include the full nested path if declared inline alias: 'name.first' } } });复制代码

模式配置

schema是有不少配置的,你能够在定义Schema的时候配置,或者使用set方法。

new Schema({..}, options);// orconst schema = new Schema({..});
schema.set(option, value);复制代码

相关配置能够参考文档,这里举例几个可能会用到的:

  • colleciton 这个配置能够修改collection的名字(默认是使用model的复数化名称,见下面)

const dataSchema = new Schema({..}, { collection: 'data' });const dataModel = Mongoose.model('othername', dataSchema);复制代码

模式方法

(未完待续)

额外推荐:可视化客户端

固然,你能够经过命令行查看结果,可是更多人仍是习惯使用图形化的界面,这里推荐一个MongoDB的可视化客户端:robot 3T,这就是原来大名鼎鼎的RoboMongo。全平台都支持。要是以前我还真不想推荐它,由于在mac上显示实在难受,不支持retina屏幕。

可是如今,已经好了不少


免费体验云安全(易盾)内容安全、验证码等服务

更多网易技术、产品、运营经验分享请点击




相关文章:
【推荐】 Spring Cloud使用总结

相关文章
相关标签/搜索