NodeJS简易博客系统(四)Mongoose入门学习

一、模式(schemas)

1、定义schema

Mongoose的一切都始于一个Schema。每个schema映射到MongoDB的集合
(collection)和定义该集合(collection)中的文档的形式。
 

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var blogSchema = new Schema({
title: String,
author: String,
body: String,
comments: [{ body: String, date: Date }],
date: { type: Date, default: Date.now },
hidden: Boolean,
meta: {
votes: Number,
favs: Number
}
});

如果想后续添加额外的键(keys) ,使用Schema#add方法。在blogSchema每个key在我们的文件将被转换为相关SchemaType定义一个属性。允许使用的SchemaTypes:

  • String
  • Number
  • Date
  • Buffer
  • Boolean
  • Mixed
  • ObjectId
  • Array

用default来设置默认值。

2、模型创建

使用刚刚的schema定义,我们需要将我们的blogschema转成我们可以用的模型。
为此,我们通过 mongoose.model(modelName, schema) :
 

var Blog = mongoose.model('Blog', blogSchema);

3、自定义文档实例方法

// define a schema
var animalSchema = new Schema({ name: String, type: String });
// assign a function to the "methods" object of our animalSchema
animalSchema.methods.findSimilarTypes = function(cb) {
return this.model('Animal').find({ type: this.type }, cb);
};

调用:

var Animal = mongoose.model('Animal', animalSchema);
var dog = new Animal({ type: 'dog' });
dog.findSimilarTypes(function(err, dogs) {
console.log(dogs); // woof
});

4、自定义文档静态实例方法

// assign a function to the "statics" object of our animalSchema
animalSchema.statics.findByName = function(name, cb) {
return this.find({ name: new RegExp(name, 'i') }, cb);
};
var Animal = mongoose.model('Animal', animalSchema);
Animal.findByName('fido', function(err, animals) {
console.log(animals);
});

二、模型(models)

Models 是从 Schema 编译来的构造函数。 它们的实例就代表着可以从数据库保存和读取的 documents。 从数据库创建和读取 document 的所有操作都是通过 model 进行的。

1、简单实例

schema文件

var mongoose = require("mongoose");
module.exports = new mongoose.Schema({
    username: String,
    password: String,
    isadmin:{
        type:Boolean,
        default:false
    }
});

model文件

var mongoose = require("mongoose");
var userschama = require("../schemas/users");
module.exports = mongoose.model("User",userschama);

2、CRUD操作

1、Create

model对象.save()

2、Retrieve

用 mongoose 查询文档相当容易啦,它支持 MongoDB 的高级( rich )查询语法。 查询文档可以用 model 的 find, findById, findOne, 和 where 这些静态方法。查询对象的size为small并且创建时间为近一年的数据:

model对象.find({ size: 'small' }).where('createdDate').gt(oneYearAgo).exec(callback);。

3、Update

model 的 update 方法可以修改数据库中的文档,不过不会把文档返回给应用层。如果想更新单独一条文档并且返回给应用层,可以使用 findOneAndUpdate 方法。

4、Delete

model 的 remove 方法可以删除所有匹配查询条件( conditions )的文档。

Tank.remove({ size: 'large' }, function (err) {
  if (err) return handleError(err);
  // todo after removing
});

三、文档(documents)

1、更新

Document 更新的方法同样有很多,我们先看看一个传统的实现,使用 findById:

Object.findById(id, function (err, object) {
  if (err) return handleError(err);

  object.size = 'large';
  object.save(function (err, updatedObject) {
    if (err) return handleError(err);
    res.send(updatedObject);
  });
});

这个方法先检索数据,接着更新(使用了 save)。 如果仅仅需要更新而不需要获取该数据, Model#update 就很适合:

Object.update({ _id: id }, { $set: { size: 'large' }}, callback);

如果我们确实需要返回文档,这个方法更适合:

Object.findByIdAndUpdate(id, { $set: { size: 'large' }}, { new: true }, function (err, object) {
  if (err) return handleError(err);
  res.send(object);
});

findAndUpdate/Remove 系列静态方法查找并返回最多1个文档。
注意:findAndUpdate/Remove 不会修改数据库时执行任何钩子或验证。 可以使用 runValidators 选项 获取一个验证的限制子集(待修改)。 但是你需要钩子和全文档验证,还是先 query 后 save 吧。

2、覆盖

可以用 .set() 覆盖整个文档。如果你要修改 在中间件中被保存的文档,这样就很方便。

Object.findById(id, function (err, object) {
  if (err) return handleError(err);
  // Now `otherObject` is a copy of `object`
  otherObject.set(object);
});

3、子文档(Subdocument)

子文档是指嵌套在另一个文档中的文档。 在 Mongoose 中,这意味着你可以在里嵌套另一个 schema。 Mongoose 子文档有两种不同的概念:子文档数组和单个嵌套子文档。

var childSchema = new Schema({ name: 'string' });

var parentSchema = new Schema({
  // Array of subdocuments
  children: [childSchema],
  // Single nested subdocuments. Caveat: single nested subdocs only work
  // in mongoose >= 4.2.0
  child: childSchema
});

子文档与普通 document 类似。嵌套schema可以有自己的中间件、自定义检验逻辑、 虚拟值以及其他顶层schemas可用的特性。两者主要的不同点是子文档不能单独保存,他们会在他们的顶级文档保存时保存。

var Parent = mongoose.model('Parent', parentSchema);
var parent = new Parent({ children: [{ name: 'Matt' }, { name: 'Sarah' }] })
parent.children[0].name = 'Matthew';

// `parent.children[0].save()` 无操作,虽然他触发了中间件
// 但是**没有**保存文档。你需要 save 他的父文档
parent.save(callback);

子文档跟普通 document一样有save和validate中间件。调用父文档的save()会触发其所有子文档的save()中间件,validate()中间件同理。

childSchema.pre('save', function (next) {
  if ('invalid' == this.name) {
    return next(new Error('#sadpanda'));
  }
  next();
});

var parent = new Parent({ children: [{ name: 'invalid' }] });
parent.save(function (err) {
  console.log(err.message) // #sadpanda
});

子文档的 pre('save') 和 pre('validate') 中间件执行于 顶层document的pre('save') 之前,顶层 document的pre('validate')之后。 因为save()前的验证就是一个内置中间件。

// 一下代码顺序打出 1-4 
var childSchema = new mongoose.Schema({ name: 'string' });

childSchema.pre('validate', function(next) {
  console.log('2');
  next();
});

childSchema.pre('save', function(next) {
  console.log('3');
  next();
});

var parentSchema = new mongoose.Schema({
  child: childSchema,
    });

parentSchema.pre('validate', function(next) {
  console.log('1');
  next();
});

parentSchema.pre('save', function(next) {
  console.log('4');
  next();
});

查找子文档

每个子文档都有一个默认的_id 。Mongoose document数组有一个特别的id方法,这个方法只要传入_id 就能返回文档数组中特定文档。

var doc = parent.children.id(_id);

添加子文档到数组

Mongoose 数组方法有 push、 unshift、 addToSet、 及其他:

var Parent = mongoose.model('Parent');
var parent = new Parent;

// create a comment
parent.children.push({ name: 'Liesl' });
var subdoc = parent.children[0];
console.log(subdoc) // { _id: '501d86090d371bab2c0341c5', name: 'Liesl' }
subdoc.isNew; // true

parent.save(function (err) {
  if (err) return handleError(err)
  console.log('Success!');
});

create 方法可以新建子文档但不加入数组。
 

var newdoc = parent.children.create({ name: 'Aaron' });

删除子文档

每个子文档都有 remove方法。另外,对于子文档数组,有一个等效方法 .pull()。 对于单个嵌套子文档,remove()与把这个文档的值设为null等效。

// 等效于 `parent.children.pull(_id)`
parent.children.id(_id).remove();
// 等效于 `parent.child = null`
parent.child.remove();
parent.save(function (err) {
  if (err) return handleError(err);
  console.log('the subdocs were removed');
});

掌握了这些就能应付这个小项目了,如果要看详细api请参考官方文档。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值