MongoDB快速入门——建立模型与设置关联查询(Node.js)

本文阅读前提:MongoDB数据库已安装、Node环境已配置、初始化项目并安装 ‘mongoose’ 插件。


预计花费时间:20Min;

本篇文章以“文章”和“分类”为例子,来讲解MongoDB的基础用法。跟随本文代码讲解,你将学会MongoDB的模型建立和关联方法/技巧,


此篇教程学习自 -B站-全站之巅-乔尼老师- 再次感谢!真的学到很多东西。

PS1:建议MongoDB中对数据库的操作都采用await方法。

PS2:插入数据的代码只需要执行一次,否则会出现很多重复数据。

0. 连接MongoDB数据库
mongoose.connect("mongodb://localhost:27017/mongo-relation", { // mongo-relation 为数据库名称
    useUnifiedTopology: true,	// 参数的固定写法
    useNewUrlParser: true, // 参数的固定写法
});
1. mongoose.model()
// 建立文章模型 Post
const Post = mongoose.model(
    "Post",
    new mongoose.Schema({
        title: { type: String },
        body: { type: String }
    })
);

// 建立分类模型 Category
const Category = mongoose.model('Category', new mongoose.Schema({
    name: { type: String },
}))

mongoose.model()函数,传入一个参数时,代表查询模型;传入两个参数时,代表定义模型。

其中,第一个参数代表模型名称(模型建议首字母大写),第二个参数代表定义模型的结构(Schema类型,用来定义表结构)。

2. {$modelName}.insertMany()
// 向文章中插入多条数据
await Post.insertMany([
    {title: '第一篇文章', body: '内容1'},
    {title: '第二篇文章', body: '内容2'}
])

// 向分类中插入多条数据
await Category.insertMany([
    {name: 'nodejs'},
    {name: 'vuejs'}
])

{$modelName}.insertMany()函数,向数据库中插入多条数据。

3. 添加关联定义

在文章模型中添加一条属性(关联属性)。

const Post = mongoose.model(
    "Post",
    new mongoose.Schema({
        title: { type: String },
        body: { type: String },
        category: { type: mongoose.SchemaTypes.ObjectId, ref: 'Category' }, // 新添加的关联属性
    })
);

新添加的属性中:

​ ref为与之相关联的模型,用字符串表示模型名称;

​ type为对应模型(Category分类模型)中的元素id,其中的 “mongoose.SchemaTypes.ObjectId” 是固定写法,不用去理解,记住就好。

4. 将文章和分类做关联(并查询文章对应的分类)
const cat1 = await Category.findOne({ name: 'nodejs' }) // 找出第一个分类模型
const post1 = await Post.findOne({ title: '第一篇文章' }) // 找出第一篇文章模型
const post2 = await Post.findOne({ title: '第二篇文章' }) // 找出第二篇文章模型
// 设置第一篇文章的分类
post1.category = cat1._id // 第一种写法(mongodb会默认生成"_id"字段)
post1.category = cat1 // 第二种写法
// 设置第二篇文章的分类
post2.category = cat1
await post1.save() // 保存
await post2.save()

此时我们用console.log打印出文章的内容就可以看到,已经成功关联到对应分类的id。

const posts = await Post.find()
console.log(await Post.find()) // 输出文章内容

在这里插入图片描述

但是现在只能查出关联分类的id,如果想要查出该关联分类的详细信息,就需要使用populate()关联查询方法。

const posts = await Post.find().populate('category') // 括号内的参数为字段名 String类型
console.log(await Post.find()) // 输出文章内容

这样就查出关联数据 ‘category’ 所有信息(返回一个对象)。

在这里插入图片描述

然后就可以用 对象+点+key 的形式拿到分类的name属性。

但到目前位置分类对文章还是一对多的关系,也就是说一篇文章只能对应一个分类,一个分类对应多个文章。可是在现实生活中,一篇文章很可能有多个分类,那么这个时候,我们就需要修改文章模型的定义。

const Post = mongoose.model(
    "Post",
    new mongoose.Schema({
        title: { type: String },
        body: { type: String },
        // 之前的定义方法 一篇文章只能对应一个分类
        // category: { type: mongoose.SchemaTypes.ObjectId, ref: 'Category' },
        // 现在的定义方法 一篇文章能对应多个分类
        categories: [{ type: mongoose.SchemaTypes.ObjectId, ref: 'Category' }], // 数组包裹
    })
);

这里用了一个数组将这个字段包裹起来,就实现了一篇文章对应多个分类的功能。

那么我们在做分类关联时候的代码,也要发生相应的变化。

const cat1 = await Category.findOne({ name: 'nodejs' }) // 找出第一个分类模型
const cat2 = await Category.findOne({ name: 'vuejs' }) // 找出第二个分类模型
const post1 = await Post.findOne({ title: '第一篇文章' }) // 找出第一篇文章模型
const post2 = await Post.findOne({ title: '第二篇文章' }) // 找出第二篇文章模型
//配置分类
post1.categories = [cat1, cat2]
post2.categories = [cat2]
await post1.save()
await post2.save()

const posts = await Post.find().populate('categories')
console.log(posts[0], posts[1]) // 为了方便显示 这里分别查出两个数据

打印结果后发现,多对多的关联查询已经实现了,每篇文章可以关联多个分类,也可以关联单个分类,根据传入数组的元素个数而定。

在这里插入图片描述

5. 查询每个分类下的文章(难点)

反过来查询每个分类下的文章,如果依旧使用上述方法查询,我们会发现分类模型中并没有Post字段,无法做到关联查询。所以我们需要在分类模型中定义一个 虚拟字段

为了方便阅读,我们将之前定义Category模型时的第二个参数拆分出来,命名为 CategorySchema

并使用 virtual 添加一个虚拟字段,其中四个参数的意义可以用一句话简单说明:

第一次可能读不懂,没关系,多读几遍。

将本模型(Category)的 ‘_id’ 字段关联到外部模型(Post)的 ‘categories’ 字段上

// 定义Category模型时的第二个参数
const CategorySchema = new mongoose.Schema({
    name: { type: String },
})
// 添加一个虚拟字段 posts
CategorySchema.virtual('posts', {
    localField: '_id', // 本地键
    ref: 'Post', // 参考模型
    foreignField: 'categories', // 外部键
    justOne: false // 是否返回单条数据
})
const Category = mongoose.model('Category', CategorySchema)

此时已经关联成功了,我们输出结果。

但是在输出时会遇到一个问题,因为mongodb的机制,在输出时候会默认隐藏虚拟属性,所以输出语句也要稍作更改。

const cats = await Category.find().populate('posts')
console.log(cats[0].posts) // 输出时同时输出虚拟字段
console.log(cats[1].posts) // 输出时同时输出虚拟字段

查询成功,第一个分类的查询结果:

在这里插入图片描述

第二个分类的查询结果:

在这里插入图片描述

当然,还有其他办法来避免mongo的隐藏机制,但并不是本篇文章的重点,就不在这里讨论了。

至此,mongodb的基本关联查询就完成了。

你学会了吗~

最后,当然要附上源码啦!

const mongoose = require("mongoose");

mongoose.connect("mongodb://localhost:27017/mongo-relation", {
    useUnifiedTopology: true,
    useNewUrlParser: true,
});

// 建立文章模型 Post
const Post = mongoose.model(
    "Post",
    new mongoose.Schema({
        title: { type: String },
        body: { type: String },
        // category: { type: mongoose.SchemaTypes.ObjectId, ref: 'Category' },
        categories: [{ type: mongoose.SchemaTypes.ObjectId, ref: 'Category' }],
    })
);

// 建立分类模型 Category
const CategorySchema = new mongoose.Schema({
    name: { type: String },
})
// 添加一个虚拟字段 posts
CategorySchema.virtual('posts', {
    localField: '_id', // 本地键
    ref: 'Post', // 参考模型
    foreignField: 'categories', // 外键
    justOne: false // 是否返回单条数据
})
const Category = mongoose.model('Category', CategorySchema)

async function main() {
    // 向文章中插入多条数据
    // await Post.insertMany([
    //     {title: '第一篇文章', body: '内容1'},
    //     {title: '第二篇文章', body: '内容2'}
    // ])

    // 向分类中插入多条数据
    // await Category.insertMany([
    //     {name: 'nodejs'},
    //     {name: 'vuejs'}
    // ])

    // const cat1 = await Category.findOne({ name: 'nodejs' }) // 找出第一个分类模型
    // const cat2 = await Category.findOne({ name: 'vuejs' }) // 找出第二个分类模型
    // const post1 = await Post.findOne({ title: '第一篇文章' }) // 找出第一篇文章模型
    // const post2 = await Post.findOne({ title: '第二篇文章' }) // 找出第二篇文章模型
    // //配置分类
    // post1.categories = [cat1, cat2]
    // post2.categories = [cat2]
    // await post1.save()
    // await post2.save()

    // const posts = await Post.find().populate('categories')
    // console.log(posts[0], posts[1]) // 为了方便显示 这里分别查出两个数据

    const cats = await Category.find().populate('posts')
    console.log(cats[0].posts)
}

main();

共勉!

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
MongoDB Node.js 驱动程序允许Node.js应用程序连接到MongoDB,并使用异步JavaScript API与MongoDB集群进行通信。这意味着您可以在不等待处理线程空闲的情况下执行操作。 要在Node.js中使用MongoDB,您需要安装官方的MongoDB Node.js驱动程序。您可以使用npm来安装该驱动程序。然后,您可以使用该驱动程序提供的API来连接到MongoDB数据库并进行各种操作。 首,您需要通过连接字符串指定MongoDB的连接地址。例如,您可以使用以下连接字符串来连接到本地MongoDB实例: ```javascript mongodb://localhost:27017/mydatabase ``` 然后,您可以使用驱动程序提供的`MongoClient`类来连接到MongoDB数据库。以下是一个简单示例: ```javascript const MongoClient = require('mongodb').MongoClient; const uri = "mongodb://localhost:27017/mydatabase"; const client = new MongoClient(uri, { useNewUrlParser: true }); client.connect(err => { // 在这里进行数据库操作 const collection = client.db("mydatabase").collection("mycollection"); // 插入文档 collection.insertOne({ name: "John", age: 25 }, (err, result) => { if (err) throw err; console.log("插入成功"); // 查询文档 collection.find({ age: { $gt: 20 } }).toArray((err, docs) => { if (err) throw err; console.log(docs); // 关闭连接 client.close(); }); }); }); ``` 通过使用MongoDB Node.js驱动程序,您可以执行各种操作,如插入文档、查询文档、更新文档和删除文档等。您还可以使用更高级的功能,如聚合管道和索引等。 希望这个简单的示例可以帮助您开始使用MongoDBNode.js进行开发。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [MongoDB NodeJS Driver:官方 MongoDB Node.js 驱动程序-开源](https://download.csdn.net/download/weixin_42117116/20351838)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [基于MongoDB+node.js搭建简易后端接口服务器](https://blog.csdn.net/qq_56108448/article/details/125408255)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Node.js 连接 MongoDB](https://blog.csdn.net/weixin_47477471/article/details/128697965)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值