Mongoose中document与object的区别示例详解
发布时间 - 2026-01-11 03:17:34 点击率:次前言

本文主要给大家总结介绍了关于Mongoose中document与object区别的相关内容,分享出来供大家参考学习,其实这个问题其实是mongoose非常常见的问题,经常有很多以前没遇到这个问题的人都会被这个问题弄得怀疑人生。
我们先介绍一些问题的背景。
先看下面一段代码:
router.get('/', function(req, res, next) {
// res.render('index', { title: 'Express' });
const model = mongoose.model('realestate');
const queryCretia = {};
model.find(queryCretia, (err, docs) => {
res.render('index', {
title: 'express',
docs: docs
})
})
});
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<h1><%= title %></h1>
<p>Welcome to <%= title %></p>
<!-- <%= docs %> -->
<ul>
<% docs.forEach(function(doc){ %>
<li><%= doc.type %></li>
<% }) %>
</ul>
</body>
</html>
在第一段代码中,通过model.find我们应该能够获取到根据queryCriteria获取的结果,结果应该是一个对象数组,类似于这样:
[{
"_id" : ObjectId("59bdeadb2a5c612514ee7970"),
"title" : "好楼层,中等装修,满5年,*实拍",
"type" : "2室1厅",
"square" : "75.42平",
"direction" : "朝南",
"floor" : "中区/6层",
"unitPrice" : 47732,
"totalPrice" : 360,
"location" : null,
"specialExplain" : "满五",
"url" : "http://sh.lianjia.com//ershoufang/sh4528035.html",
"station" : "江杨北路",
"line" : "3号线",
"updateTime" : "2017-09-17 11:24:11"
}
{
"_id" : ObjectId("59bdeadb2a5c612514ee7971"),
"title" : "南北户型,厨卫全明,高区采光好,装修精美",
"type" : "2室2厅",
"square" : "90.92平",
"direction" : "朝南北",
"floor" : "高区/6层",
"unitPrice" : 46194,
"totalPrice" : 420,
"location" : null,
"specialExplain" : "满五",
"url" : "http://sh.lianjia.com//ershoufang/sh4546221.html",
"station" : "江杨北路",
"line" : "3号线",
"updateTime" : "2017-09-17 11:24:11"
}]
预期index.ejs应该渲染的页面是一个ul渲染的结果,类似于
- 2室1厅
- 2室2厅
当然,理想很丰满,现实很骨感。我就是死活渲染不出来doc.type。照理说应该是不可能的,在index.ejs中doc就是一个对象,我为什么不能获取doc的type属性呢?这不合理,太不合理了!
老实说,这个问题我之间也是遇到过,当初我是想修改这个doc的属性,但是死活没有办法修改,当初也是花了很久找到原因。这次我就把这个问题好好地研究一下。
先说结果,以及解决方法把。我比较喜欢剧透。愿意是因为再次返回的doc是属于Document的实例,而不是一个普通的对象。也就是说它和普通的对象是不一样的,它没有普通对象的一些方法,普通对象也没有它身上的一些方法。
解决方案有几种,不过究其根本都是将这种document转化为普通的对象:
方法1:
利用toObject方法
docs.forEach(doc => {
return doc.toObject();
})
方法2:
利用JSON方法,这是我想到的一个方法,具体深层原因在这就不展开了:
docs = JSON.stringify(docs); docs = JSON.parse(docs);
方法3:
利用lean方法:
model.find().lean().exec((err, docs) => {
....
})
上述的三种方法应该都能成功将find获取的结果转化为普通的对象。
但是我还想知道到底document和一个普通的对象到底有什么区别,区别在哪里呢?
我们假设find获取的结果是docs,转化为普通对象的结果是docs1。现在我们就看一看这二者的区别。理论上docs和docs1都应该是数组,而它们中元素都应该是一个对象,我们先来看看是不是这样呢?
console.log(Object.prototype.toString.call(docs)); consoele.log(Object.prototype.toString.call(docs[0])); console.log(Object.prototype.toString.call(docs1)); console.log(Object.prototype.toString.call(docs1[0]))
我们通过上述方法可以获取docs以及docs1的类型以及其中元素的类型,结果是:
[object Array] [object Object] [object Array] [object Object]
和我们预想中的一模一样,那问题不在这,那我们就探究探究docs[0]以及docs1[0]的原型把,看看它的原型到底是什么呢?知道JS的人,应该都知道JS中的原型链。在此,我们就通过__proto__来粗暴地获取对象的原型:
console.dir(doc[0].__proto__); console.dir(docs[0].__proto__);
结果是:
model {
db:
NativeConnection {
base:
Mongoose {
connections: [Array],
models: [Object],
modelSchemas: [Object],
options: [Object],
plugins: [Array] },
collections: { realestates: [Object] },
models: { realestate: [Object] },
config: { autoIndex: true },
replica: false,
hosts: null,
host: '127.0.0.1',
port: 27017,
user: undefined,
pass: undefined,
name: 'real_estate_info',
options:
{ db: [Object],
auth: {},
server: [Object],
replset: [Object],
mongos: undefined },
otherDbs: [],
_readyState: 1,
_closeCalled: false,
_hasOpened: true,
_listening: false,
db:
Db {
domain: null,
_events: [Object],
_eventsCount: 6,
_maxListeners: undefined,
s: [Object],
serverConfig: [Getter],
bufferMaxEntries: [Getter],
databaseName: [Getter],
_listening: true },
_events:
{ connected: [Function],
error: [Function: bound bound consoleCall],
disconnected: [Function: bound bound consoleCall],
reconnected: [Function: bound bound consoleCall] },
_eventsCount: 4 },
discriminators: undefined,
id: [Getter/Setter],
__v: [Getter/Setter],
_id: [Getter/Setter],
schema:
Schema {
obj: undefined,
paths: { _id: [Object], __v: [Object] },
aliases: {},
subpaths: {},
virtuals: { id: [Object] },
singleNestedPaths: {},
nested: {},
inherits: {},
callQueue: [ [Array], [Array], [Array], [Array], [Array], [Array] ],
_indexes: [],
methods: {},
statics: {},
tree: { _id: [Object], __v: [Function: Number], id: [Object] },
query: {},
childSchemas: [],
plugins: [ [Object], [Object], [Object], [Object] ],
s: { hooks: [Object], kareemHooks: [Object] },
options:
{ retainKeyOrder: false,
typeKey: 'type',
id: true,
noVirtualId: false,
_id: true,
noId: false,
validateBeforeSave: true,
read: null,
shardKey: null,
autoIndex: null,
minimize: true,
discriminatorKey: '__t',
versionKey: '__v',
capped: false,
bufferCommands: true,
strict: true,
pluralization: true },
'$globalPluginsApplied': true,
_requiredpaths: [] },
collection:
NativeCollection {
collection: Collection { s: [Object] },
opts: { bufferCommands: true, capped: false },
name: 'realestates',
collectionName: 'realestates',
conn:
NativeConnection {
base: [Object],
collections: [Object],
models: [Object],
config: [Object],
replica: false,
hosts: null,
host: '127.0.0.1',
port: 27017,
user: undefined,
pass: undefined,
name: 'real_estate_info',
options: [Object],
otherDbs: [],
_readyState: 1,
_closeCalled: false,
_hasOpened: true,
_listening: false,
db: [Object],
_events: [Object],
_eventsCount: 4 },
queue: [],
buffer: false,
emitter:
EventEmitter {
domain: null,
_events: {},
_eventsCount: 0,
_maxListeners: undefined } },
'$__original_save': { [Function] numAsyncPres: 0 },
save: { [Function: wrappedPointCut] '$originalFunction': '$__original_save', '$isWrapped': true },
_pres:
{ '$__original_save': [ [Object], [Object], [Object] ],
'$__original_remove': [ [Object] ] },
_posts: { '$__original_save': [], '$__original_remove': [] },
'$__original_remove': { [Function] numAsyncPres: 1 },
remove:
{ [Function: wrappedPointCut]
'$originalFunction': '$__original_remove',
'$isWrapped': true },
'$__original_validate': [Function],
validate:
{ [Function: wrappedPointCut]
'$originalFunction': '$__original_validate',
'$isWrapped': true } }
以及
{}
很显然,问题就是在这里,docs[0]和docs[0]的原型并不是一个东西。而js中对象通过.或者是[]访问属性都是调用了Object中的某个方法,但具体什么方法我不太记得。然而docs中的原型或者其原型的原型也是没有这个方法的,因此他就没办法去访问这个属性。
其实docs[0].__proto__.__proto__是Model,docs[0].__proto__.__proto__.__proto__是Document,docs[0].__proto__.__proto__.__proto__.__proto__才是{}。
至此,这个问题引起的一系列的探究也是告一段落了。其实Mongoose还有另外一些奇怪的地方,被人所诟病,在此也不一一细数了。从问题的发现,到写这篇文章大概花了大半天的时间,以前遇到问题就找到解决办法就停止了,但是这一次通过这样深入地去发现,可能就会发掘到更多的东西。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。
# mongoose
# document
# object
# Mongoose学习全面理解(推荐)
# 这个问题
# 是一个
# 的人
# 都是
# 转化为
# 结果是
# 在这
# 在此
# 花了
# 北路
# 类似于
# 朝南
# 都应
# 一个普通
# 我是
# 当初
# 就会
# 在这里
# 是因为
# 不可能
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Edge浏览器怎么启用睡眠标签页_节省电脑内存占用优化技巧
香港服务器网站推广:SEO优化与外贸独立站搭建策略
Laravel如何理解并使用服务容器(Service Container)_Laravel依赖注入与容器绑定说明
Win11怎么关闭透明效果_Windows11辅助功能视觉效果设置
Android自定义listview布局实现上拉加载下拉刷新功能
JS中页面与页面之间超链接跳转中文乱码问题的解决办法
Laravel如何使用Guzzle调用外部接口_Laravel发起HTTP请求与JSON数据解析【详解】
Claude怎样写结构化提示词_Claude结构化提示词写法【教程】
宙斯浏览器文件分类查看教程 快速筛选视频文档与图片方法
什么是javascript作用域_全局和局部作用域有什么区别?
JS碰撞运动实现方法详解
laravel怎么为API路由添加签名中间件保护_laravel API路由签名中间件保护方法
如何在服务器上配置二级域名建站?
Laravel如何实现邮箱地址验证功能_Laravel邮件验证流程与配置
Laravel如何实现数据库事务?(DB Facade示例)
如何在 Python 中将列表项按字母顺序编号(a.、b.、c. …)
Laravel如何实现本地化和多语言支持?(i18n教程)
lovemo网页版地址 lovemo官网手机登录
品牌网站制作公司有哪些,买正品品牌一般去哪个网站买?
在centOS 7安装mysql 5.7的详细教程
Laravel如何实现API速率限制?(Rate Limiting教程)
node.js报错:Cannot find module 'ejs'的解决办法
Laravel Vite是做什么的_Laravel前端资源打包工具Vite配置与使用
详解vue.js组件化开发实践
Android实现代码画虚线边框背景效果
Laravel如何自定义错误页面(404, 500)?(代码示例)
Laravel Sail是什么_基于Docker的Laravel本地开发环境Sail入门
javascript和jQuery中的AJAX技术详解【包含AJAX各种跨域技术】
canvas 画布在主流浏览器中的尺寸限制详细介绍
如何实现javascript表单验证_正则表达式有哪些实用技巧
谷歌浏览器如何更改浏览器主题 Google Chrome主题设置教程
Laravel路由怎么定义_Laravel核心路由系统完全入门指南
Python函数文档自动校验_规范解析【教程】
Laravel如何与Vue.js集成_Laravel + Vue前后端分离项目搭建指南
Laravel怎么自定义错误页面_Laravel修改404和500页面模板
html5audio标签播放结束怎么触发事件_onended回调方法【教程】
音乐网站服务器如何优化API响应速度?
Laravel怎么实现微信登录_Laravel Socialite第三方登录集成
Laravel Blade模板引擎语法_Laravel Blade布局继承用法
长沙做网站要多少钱,长沙国安网络怎么样?
LinuxShell函数封装方法_脚本复用设计思路【教程】
Linux系统命令中tree命令详解
Laravel怎么使用Markdown渲染文档_Laravel将Markdown内容转HTML页面展示【实战】
Laravel Livewire是什么_使用Laravel Livewire构建动态前端界面
详解Android——蓝牙技术 带你实现终端间数据传输
Laravel怎么判断请求类型_Laravel Request isMethod用法
Laravel如何安装使用Debugbar工具栏_Laravel性能调试与SQL监控插件【步骤】
如何在建站之星绑定自定义域名?
猪八戒网站制作视频,开发一个猪八戒网站,大约需要多少?或者自己请程序员,需要什么程序员,多少程序员能完成?
如何在阿里云购买域名并搭建网站?

