Mongoose中document與object的區(qū)別示例詳解
前言
本文主要給大家總結(jié)介紹了關(guān)于Mongoose中document與object區(qū)別的相關(guān)內(nèi)容,分享出來供大家參考學(xué)習(xí),其實這個問題其實是mongoose非常常見的問題,經(jīng)常有很多以前沒遇到這個問題的人都會被這個問題弄得懷疑人生。
我們先介紹一些問題的背景。
先看下面一段代碼:
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我們應(yīng)該能夠獲取到根據(jù)queryCriteria獲取的結(jié)果,結(jié)果應(yīng)該是一個對象數(shù)組,類似于這樣:
[{
"_id" : ObjectId("59bdeadb2a5c612514ee7970"),
"title" : "好樓層,中等裝修,滿5年,上門實拍",
"type" : "2室1廳",
"square" : "75.42平",
"direction" : "朝南",
"floor" : "中區(qū)/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" : "南北戶型,廚衛(wèi)全明,高區(qū)采光好,裝修精美",
"type" : "2室2廳",
"square" : "90.92平",
"direction" : "朝南北",
"floor" : "高區(qū)/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"
}]
預(yù)期index.ejs應(yīng)該渲染的頁面是一個ul渲染的結(jié)果,類似于
- 2室1廳
- 2室2廳
當(dāng)然,理想很豐滿,現(xiàn)實很骨感。我就是死活渲染不出來doc.type。照理說應(yīng)該是不可能的,在index.ejs中doc就是一個對象,我為什么不能獲取doc的type屬性呢?這不合理,太不合理了!
老實說,這個問題我之間也是遇到過,當(dāng)初我是想修改這個doc的屬性,但是死活沒有辦法修改,當(dāng)初也是花了很久找到原因。這次我就把這個問題好好地研究一下。
先說結(jié)果,以及解決方法把。我比較喜歡劇透。愿意是因為再次返回的doc是屬于Document的實例,而不是一個普通的對象。也就是說它和普通的對象是不一樣的,它沒有普通對象的一些方法,普通對象也沒有它身上的一些方法。
解決方案有幾種,不過究其根本都是將這種document轉(zhuǎn)化為普通的對象:
方法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) => {
....
})
上述的三種方法應(yīng)該都能成功將find獲取的結(jié)果轉(zhuǎn)化為普通的對象。
但是我還想知道到底document和一個普通的對象到底有什么區(qū)別,區(qū)別在哪里呢?
我們假設(shè)find獲取的結(jié)果是docs,轉(zhuǎn)化為普通對象的結(jié)果是docs1?,F(xiàn)在我們就看一看這二者的區(qū)別。理論上docs和docs1都應(yīng)該是數(shù)組,而它們中元素都應(yīng)該是一個對象,我們先來看看是不是這樣呢?
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的類型以及其中元素的類型,結(jié)果是:
[object Array] [object Object] [object Array] [object Object]
和我們預(yù)想中的一模一樣,那問題不在這,那我們就探究探究docs[0]以及docs1[0]的原型把,看看它的原型到底是什么呢?知道JS的人,應(yīng)該都知道JS中的原型鏈。在此,我們就通過__proto__來粗暴地獲取對象的原型:
console.dir(doc[0].__proto__); console.dir(docs[0].__proto__);
結(jié)果是:
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中對象通過.或者是[]訪問屬性都是調(diào)用了Object中的某個方法,但具體什么方法我不太記得。然而docs中的原型或者其原型的原型也是沒有這個方法的,因此他就沒辦法去訪問這個屬性。
其實docs[0].__proto__.__proto__是Model,docs[0].__proto__.__proto__.__proto__是Document,docs[0].__proto__.__proto__.__proto__.__proto__才是{}。
至此,這個問題引起的一系列的探究也是告一段落了。其實Mongoose還有另外一些奇怪的地方,被人所詬病,在此也不一一細(xì)數(shù)了。從問題的發(fā)現(xiàn),到寫這篇文章大概花了大半天的時間,以前遇到問題就找到解決辦法就停止了,但是這一次通過這樣深入地去發(fā)現(xiàn),可能就會發(fā)掘到更多的東西。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
nodejs中使用worker_threads來創(chuàng)建新的線程的方法
這篇文章主要介紹了nodejs中使用worker_threads來創(chuàng)建新的線程的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01
Nginx設(shè)置為Node.js的前端服務(wù)器方法總結(jié)
在本篇文章中小編給大家分享了關(guān)于Nginx設(shè)置為Node.js的前端服務(wù)器的方法和實例,需要的朋友們學(xué)習(xí)下。2019-03-03
node.js學(xué)習(xí)筆記之koa框架和簡單爬蟲練習(xí)
這篇文章主要介紹了node.js學(xué)習(xí)筆記之koa框架和簡單爬蟲練習(xí),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-12-12
express結(jié)合nodejs開啟服務(wù)示例模版
這篇文章主要為大家展現(xiàn)了express結(jié)合nodejs開啟服務(wù)的代碼示例模版,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
nodejs調(diào)用cmd命令實現(xiàn)復(fù)制目錄
本文給大家介紹的是如何在nodejs中調(diào)用CMD命令,從而實現(xiàn)目錄的復(fù)制,非常的實用,有需要的小伙伴可以參考下。2015-05-05
node.js中的buffer.Buffer.isBuffer方法使用說明
這篇文章主要介紹了node.js中的buffer.Buffer.isBuffer方法使用說明,本文介紹了buffer.Buffer.isBuffer的方法說明、語法、接收參數(shù)、使用實例和實現(xiàn)源碼,需要的朋友可以參考下2014-12-12
可能是全網(wǎng)最詳細(xì)的nodejs卸載和安裝教程
npm的中文意思為"node包管理器",是Node.js平臺的默認(rèn)包管理工具,會隨著Nodejs一起安裝,npm管理對應(yīng)node.js的第三方插件,下面這篇文章主要給大家介紹了關(guān)于nodejs卸載和安裝教程的相關(guān)資料,這可能全網(wǎng)最詳細(xì)的教程了,需要的朋友可以參考下2023-05-05

