摘要:愿意是因為再次返回的是屬于的實例,而不是一個普通的對象。現在我們就看一看這二者的區別。至此,這個問題引起的一系列的探究也是告一段落了。其實還有另外一些奇怪的地方,被人所詬病,在此也不一一細數了。
這個問題其實是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 }) }) });
<%= title %> <%= title %>
Welcome to <%= title %>
在第一段代碼中,通過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還有另外一些奇怪的地方,被人所詬病,在此也不一一細數了。從問題的發現,到寫這篇文章大概花了大半天的時間,以前遇到問題就找到解決辦法就停止了,但是這一次通過這樣深入地去發現,可能就會發掘到更多的東西。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91870.html
摘要:使用可以實現在一個中填充其他的。表示關聯注意被關聯的的必須是和才有效。類型的時,格式如為表示不填充,為時表示填充。以鍵值對的形式表示。回調函數,接收兩個參數,錯誤和填充完的。參考數據庫的最簡單實現使用之原文鏈接 Mongoose 是 MongoDB 的 ODM(Object Document Mapper)。 什么是ODM? 其實和ORM(Object Relational Mapp...
摘要:使用可以實現在一個中填充其他的。表示關聯注意被關聯的的必須是和才有效。封裝了很多查詢的方法,使得對數據庫的操作變得簡單啦。這里分享一下方法用法。類型的時,格式如為表示不填充,為時表示填充。類型,可選,指定附加的查詢條件。 Mongoose 是 MongoDB 的 ODM(Object Document Mapper)。 什么是ODM? 其實和ORM(Object Relational...
摘要:轉自一快速通道名詞解釋一種以文件形式存儲的數據庫模型骨架,不具備數據庫的操作能力由發布生成的模型,具有抽象屬性和行為的數據庫操作對由創建的實體,他的操作也會影響數據庫注意本學習文檔采用嚴格命名方式來區別不同對象,例如的文本屬性的數據庫模型實 轉自 https://cnodejs.org/topic/504... 一、快速通道 1.1 名詞解釋 Schema : 一種以文件形式存儲的...
摘要:是在環境下對進行便捷操作的對象模型工具因此,要使用,則必須安裝環境以及數據庫。使操作更簡單便捷。找到記錄,并且將遞增,返回后的為之前的。這個屬性很有用,對數字直接進行增減。,要返回的字段與的第二個參數一致。 Mongoose是在node.js環境下對mongodb進行便捷操作的對象模型工具 因此,要使用mongoose,則必須安裝node.js環境以及mongodb數據庫。mongoo...
摘要:返回的是轉換為字符串后的值。默認行為禁止在一個中如果沒有定義域,那么將會默認分配一個域。通過在中設置這個字段可以阻止生成獲得。我們也能設置其它的安全等級如表示如果秒內寫操作沒有完成,將會超時。在,和方法只檢查頂級的的選項設置。 原文出處 名詞解釋 Schema: 一種以文件形式存儲的數據庫模型骨架,不具備數據庫的操作能力 Model: 由Schema編譯而成的假想(fancy)構造器...
閱讀 3420·2021-11-15 11:39
閱讀 1552·2021-09-22 10:02
閱讀 1309·2021-08-27 16:24
閱讀 3596·2019-08-30 15:52
閱讀 3412·2019-08-29 16:20
閱讀 824·2019-08-28 18:12
閱讀 550·2019-08-26 18:27
閱讀 716·2019-08-26 13:32