Mongoose中document与object的区别示例详解
前言
本文主要给大家总结介绍了关于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:
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的区别示例详解
-
jquery中的$(document).ready()与window.onload的区别_jquery
-
php中const与define的使用区别 详解_PHP教程
-
PHP中isset、empty的用法与区别示例详解
-
nodejs中的__filename与__dirname具体示例及区别讲解
-
jQuery中document与window以及load与ready 区别详解_jquery
-
探讨C#中Dispose方法与Close方法的区别详解
-
JavaScript中indexOf与search的区别详解
-
C#中按引用传递与按值传递的区别,以及ref与out关键字的用法详解
-
ASP.NET中readonly与const的区别详解