用户画像4:标签数据开发

前言
本项目基于: egg.js

安装配置
1.安装依赖
npm install egg-mongoose --save
2.开启插件
# /config/plugin.ts
import { EggPlugin } from 'egg';

const plugin: EggPlugin = {
mongoose: {
enable: true,
package: 'egg-mongoose',
},
};

export default plugin;
3.插件配置
# /config/config.default.ts
import { EggAppConfig, PowerPartial } from 'egg';

export default () => {
const config = {} as PowerPartial<EggAppConfig>;

config.mongoose = {
url: process.env.MONGO_URL || 'mongodb://localhost:27017/blog',
options: {
poolSize: 40,
},
};

return {
...config,
};
};
本项目锁使用的环境:

"egg-mongoose": "3.2.0"

node -v
v10.5.0
分割线,下面是重点

使用
一.创建 Model(模型)
eggjs 在 /app/model/ 下定义数据模型

以我的 blog 项目为例,假设有一个 tag 表、article 表,article 表通过 tag_id 关联 tag 表如下:

1.tag 表
# /app/model/tag.ts
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const PostSchema = new Schema({
tag_name: {
type: String,
required: true,
},
created_time: {
type: Date,
default: new Date(),
},
updated_time: {
type: Date,
default: new Date(),
},
});
return mongoose.model('Tag', PostSchema);
};
2.article 表
通过 tag_id 关联 tag 表

# /app/model/article.ts
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const PostSchema = new Schema({
tag_id: {
type: Schema.Types.ObjectId,
required: true,
ref: 'Tag',
},
title: {
type: String,
required: true,
},
status: {
type: Boolean,
default: false,
},
content: {
type: String,
default: '',
},
weather: {
type: String,
default: '',
},
image: {
type: String,
default: '',
},
images: {
type: Array,
default: [],
},
pv: {
type: Number,
default: 0,
},
created_time: {
type: Date,
default: new Date(),
},
updated_time: {
type: Date,
default: new Date(),
},
});
return mongoose.model('Article', PostSchema);
};
更多 schema 使用:mongoose schema

二.简单常用
eggjs 中,一般在 service 层操作 model 层,返回的是一个 promise,so 可以直接用 await 同步编程

我们先定义 search 为查询条件

1.增
新增一篇文章

# article 为对象
const article: Article;
this.ctx.model.Article.create(article);
批量新增

# article 为数组
const article: Array<Article>;
this.ctx.model.Article.create(article);
2.删
删除一篇文章

this.ctx.model.Article.deleteOne(search);
删除多篇文章

this.ctx.model.Article.remove(search);
3.查
查找一篇文章

this.ctx.model.Article.findOne(search);
查找多篇

# search 为空 或者空对象返回全部
this.ctx.model.Article.find(search);
分页查找 skip、limit

this.ctx.model.Article.find(search)
.sort({ _id: -1 }) # 按照创建时间倒序
.skip(page_size * (current_page - 1)) # 跳过前n个数据
.limit(page_size); # 限制n个数据
4.改
替换文章内容

# 注意,是直接全部替换为 new_data
# findOneAndUpdate默认返回旧的数据
# 若需要部分更新,应使用 $set 操作符
return await this.ctx.model.Article.findOneAndUpdate(search, new_data);
返回修改后最新的数据

# 注意第三个参数
return await this.ctx.model.Article.findOneAndUpdate(search, new_data, { new: true });
再次分割线,下面是重点中的重点

三.操作符
&dollar;set
&dollar;set 对指定文档中的某些键进行更新,如果这个字段不存在则创建它
# 修改文章 pv为 10000
const operation: any = {
$set: {
pv: 10000,
},
};
return await this.ctx.model.Article.findOneAndUpdate(search, operation);
$gt、$lt、$gte、$lte、&dollar;ne
(>) 大于 &dollar;gt
(<) 小于 &dollar;lt
(>=) 大于等于 &dollar;gte
(<= ) 小于等于 &dollar;lte
(!==) 不等于 &dollar;ne
# 查pv大于10的文章
const search = {
pv: {
$gt: 1000,
},
};
this.ctx.model.Article.find(search);
$or、$and、$not、$nor
&dollar;or 满足任一表达式
&dollar;and 同时满足多个表达式
&dollar;not 不满足表达式
&dollar;nor 不满足任一表达式
查找 pv 大于 10 且公开的文章

const search: any = {
$and: [
{ pv: { $gt: 10 } },
{ status: true },
],
};
this.ctx.model.Article.find(search);
&dollar;inc
&dollar;inc 用来增加和减少已有键的值,只能用于 Number 类型。对于不存在的键,会自动创建相应的键,并且值为给定的值
文章 pv 自增

const operation: any = {
$inc: {
pv: 1,
},
};
this.ctx.model.Article.findOneAndUpdate(search, operation);
&dollar;push、&dollar;pull
&dollar;push 向已有的数组末尾添加一个元素,如果没有就创建一个新的数组
&dollar;pull 会删除掉数组中符合条件的元素

const operation: any = {
$push: {
images: {
content: 'hello world',
},
},
};
await this.ctx.model.Article.findOneAndUpdate(search, operation);

const operation: any = {
$pull: {
images: {
content: 'hello world',
},
},
};
await this.ctx.model.Article.findOneAndUpdate(search, operation);
&dollar;in、&dollar;nin
&dollar;in 包含
&dollar;nin 不包含
&dollar;in 类似与 js Araay includes 方法,与数组中任意一个值相等
查找 pv 在[1,2,3]的文章

const search: any = {
pv: {
$in: [ 1, 2, 3 ],
},
};
this.ctx.model.Article.find(search);
&dollar;type
&dollar;type 匹配数据类型
详细的类型请:MongoDB &dollar;type 操作符

匹配 status 字段类型为 boolean

const search: any = {
status: {
$type: 8,
},
};
this.ctx.model.Article.find(search);
&dollar;exists
&dollar;exists 判断字段是否存在
查找 status 字段存在的文章

const search: any = {
status: {
$exists: true,
},
};
this.ctx.model.Article.find(search);
&dollar;regex
&dollar;regex 正则匹配内容
正则匹配内容 123

const search: any = {
content: { $regex: '123', $options: 'i' },
};
this.ctx.model.Article.find(search);
实际上,也可以直接用字面量

const search: any = {
content: /123/g,
};
this.ctx.model.Article.find(search);
&dollar;where
&dollar;where 类似于 mysql 的 where
查找 pv 大于 20 的文章

const search: any = {
$where: 'this.pv>20',
};
this.ctx.model.Article.find(search);
四.aggregate 聚合
MongoDB 的聚合管道将 MongoDB 文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的。
常用的管道操作符:

1.&dollar;match
&dollar;match 用于过滤数据,只输出符合条件的文档。
this.ctx.model.Article.aggregate([
{ $match: search },
]);
2.&dollar;project
&dollar;project 用于修改输入文档的结构,可以用来重命名、增加或删除域
修改文档结构,只输出 content 字段

this.ctx.model.Article.aggregate([
{ $match: search },
{
$project: {
content: 1,
},
},
]);
3.&dollar;limit、&dollar;skip
&dollar;limi: 限制返回的文档数
&dollar;skip:跳过指定数量的文档
常用的分页查找

this.ctx.model.Article.aggregate([
{ $match: search },
{ $skip: page_size * (current_page - 1) },
{ $limit: page_size },
]);
4.&dollar;group
&dollar;group 将集合中的文档分组,用于统计结果。类似于 mysql group by
统计每个标签的文章总数 count

this.ctx.model.Article.aggregate([
{
$group: {
_id: '$tag_id',
count: {
$sum: 1,
},
},
},
]);
5.&dollar;sort
&dollar;sort 将输入文档排序后输出
按照文章修改时间倒序

this.ctx.model.Article.aggregate([
{ $match: search },
{ $sort: { updated_time: -1 } },
]);
6.&dollar;lookup、&dollar;unwind
&dollar;unwind 将 Array 类型字段拆分成多条,每条包含数组中的一个值
&dollar;lookup mongo3.2 版本新增,用于实现联表查询
有几个参数:

语法 解释
from 源数据表
localField 待 Join 的数据表
foreignField Join 的数据表的 match 字段
as 为输出文档的新增值命名
查找文章详情,根据 tag_id 查找 tag 表的详情

this.ctx.model.Article.aggregate([
{
$lookup: {
from: 'tags',
localField: 'tag_id',
foreignField: '_id',
as: 'tag_info',
},
},
{ $unwind: '$tag_info' },
]);

原文地址:https://www.cnblogs.com/hzcya1995/p/13268754.html