mongoose深層修改問題


https://cnodejs.org/topic/50dde64ea7e6c6171a80a678

各位大神好,好久沒寫點什么東西了,最近也是cnode社區不知道咋的了都登錄不進去,今天總算能回到這里,今天遇到這樣的一個問題,發出來咨詢下各位。 mongoose提供的schema/model/document想必大家都不陌生,model有一個update方法,現假設我的schema如下

//假設Schema對象已經從Mongoose的api中提取出來var schema =newSchema({ baseinfo:{ name:String, age:Number}, status:Number});

如果數據庫里已經存了這樣的數據 {baseinfo:{name:'loong',age:20},status:0} 我現在要做這樣的事情,只修改年齡。 我知道modelupdate方法支持mongodb原生的api,例如

//代碼1 schemaModel.update({name:'loong'},{$set:{baseinfo:{age:26}}});

$setapi原本是支持有值覆蓋/沒值不改這一套模式(我稱之為設置模式)的,即**$set后傳入什么就修改什么,如果不傳世不會被修改了,代碼1中我沒有傳入status的修改,因此執行后在數據庫的數據仍然是0。 但問題就來了,$set支持這的這模式對於層級只有一層的status很有用,但是對於有2個層級的baseinfo來說就不是這樣的了。代碼1最終運行的結果是age確實改為了26,但name屬性卻沒有了。他的理解是將baseinfo:{age:26}這個鍵值對對應的覆蓋(我稱之為覆蓋模式**)到實體上,理所當然的沒有了name咯。 當然我在問問前我肯定是要做一番研究的,我從來不會做那種自己不研究就上來問問題的。那么我要研究的課題是:如何讓mongoosemodel支持多層級屬性設置模式。在上例中,按照我所研究的課題就是,傳什么,改什么,對於深層對象也做判斷,永遠沒有覆蓋。 於是,我決定采用深層**$set**,看是否能有所效果:

//代碼2 schemaModel.update({name:'loong'},{$set:{baseinfo:{$set:{age:26}}}});

這時候,我在baseinfo后,age前又加了個**$set**,因為我覺得**$set**只查找一層,那么設置2個應該就能查找2層咯,但是結果返回錯誤,這時不被允許的。 再次查找api,嘗試了使用如下的方式:

//代碼3 schemaModel.update({name:'loong'},{$set:{‘baseinfo.age’:26}});

這時候是可以的,但是問題就來了:1.‘baseinfo.age’這樣的寫法是需要從json中轉換的,麻煩,2.我要更新baseinfo下的多個數據,就要在這里寫很多了。 有沒有既不需要轉換,同時又能解決多個數據的方式呢? 我再次看了看api,嘗試了如下的方法:

//代碼4 schemaModel.update({name:'loong'},{$set:{‘baseinfo.$’:{age:26}}});

這次代碼是通過了,但是貌似並沒有實現修改,這我就納悶了,為什么會這樣呢?查看了api,發現,對.$理解錯了,他是針對數組的操作,如果有一個數組的匹配項,則做該項的更新。 ok,嘗試了很多,發現都沒有得到自己想要的結果,那我們就退一步吧,既然model無法實現,那么document能否實現呢?我的嘗試仍然繼續:

//代碼5 schemaModel.findOne({name:'loong'},function(err,doc){ doc.set({baseinfo:{age:26}}); doc.save();});

一運行,這次真的成功了,name屬性沒有消失,而age屬性也成功的修改了。 到此實驗已經完成,我退而求其次的找到了解決問題的方法。但是我仍然很好奇,希望能有人提供線索幫忙解決以下2個問題: 1.能不能讓model也能做到多層次設置模式,而且要代碼簡單。 2.代碼5如果baseinfo中還有多層的,不知道會不會出現類似代碼1的問題,雖然實際中不會設置這么深的層次,但是還是作為一個問題,暫時沒時間研究了,希望能有人測一下。

各位大神好,好久沒寫點什么東西了,最近也是cnode社區不知道咋的了都登錄不進去,今天總算能回到這里,今天遇到這樣的一個問題,發出來咨詢下各位。 mongoose提供的schema/model/document想必大家都不陌生,model有一個update方法,現假設我的schema如下

//假設Schema對象已經從Mongoose的api中提取出來var schema =newSchema({ baseinfo:{ name:String, age:Number}, status:Number});

如果數據庫里已經存了這樣的數據 {baseinfo:{name:'loong',age:20},status:0} 我現在要做這樣的事情,只修改年齡。 我知道modelupdate方法支持mongodb原生的api,例如

//代碼1 schemaModel.update({name:'loong'},{$set:{baseinfo:{age:26}}});

$setapi原本是支持有值覆蓋/沒值不改這一套模式(我稱之為設置模式)的,即**$set后傳入什么就修改什么,如果不傳世不會被修改了,代碼1中我沒有傳入status的修改,因此執行后在數據庫的數據仍然是0。 但問題就來了,$set支持這的這模式對於層級只有一層的status很有用,但是對於有2個層級的baseinfo來說就不是這樣的了。代碼1最終運行的結果是age確實改為了26,但name屬性卻沒有了。他的理解是將baseinfo:{age:26}這個鍵值對對應的覆蓋(我稱之為覆蓋模式**)到實體上,理所當然的沒有了name咯。 當然我在問問前我肯定是要做一番研究的,我從來不會做那種自己不研究就上來問問題的。那么我要研究的課題是:如何讓mongoosemodel支持多層級屬性設置模式。在上例中,按照我所研究的課題就是,傳什么,改什么,對於深層對象也做判斷,永遠沒有覆蓋。 於是,我決定采用深層**$set**,看是否能有所效果:

//代碼2 schemaModel.update({name:'loong'},{$set:{baseinfo:{$set:{age:26}}}});

這時候,我在baseinfo后,age前又加了個**$set**,因為我覺得**$set**只查找一層,那么設置2個應該就能查找2層咯,但是結果返回錯誤,這時不被允許的。 再次查找api,嘗試了使用如下的方式:

//代碼3 schemaModel.update({name:'loong'},{$set:{‘baseinfo.age’:26}});

這時候是可以的,但是問題就來了:1.‘baseinfo.age’這樣的寫法是需要從json中轉換的,麻煩,2.我要更新baseinfo下的多個數據,就要在這里寫很多了。 有沒有既不需要轉換,同時又能解決多個數據的方式呢? 我再次看了看api,嘗試了如下的方法:

//代碼4 schemaModel.update({name:'loong'},{$set:{‘baseinfo.$’:{age:26}}});

這次代碼是通過了,但是貌似並沒有實現修改,這我就納悶了,為什么會這樣呢?查看了api,發現,對.$理解錯了,他是針對數組的操作,如果有一個數組的匹配項,則做該項的更新。 ok,嘗試了很多,發現都沒有得到自己想要的結果,那我們就退一步吧,既然model無法實現,那么document能否實現呢?我的嘗試仍然繼續:

//代碼5 schemaModel.findOne({name:'loong'},function(err,doc){ doc.set({baseinfo:{age:26}}); doc.save();});

一運行,這次真的成功了,name屬性沒有消失,而age屬性也成功的修改了。 到此實驗已經完成,我退而求其次的找到了解決問題的方法。但是我仍然很好奇,希望能有人提供線索幫忙解決以下2個問題: 1.能不能讓model也能做到多層次設置模式,而且要代碼簡單。 2.代碼5如果baseinfo中還有多層的,不知道會不會出現類似代碼1的問題,雖然實際中不會設置這么深的層次,但是還是作為一個問題,暫時沒時間研究了,希望能有人測一下。

6 回復

我覺得model直接改得好處,少了一步save()!但是第二種更自然點,找到這個文件,直接對文件下的key賦值,在保存下,也很簡單啊!即使多層,可以一直.下去(數組除外)

schemaModel.findOne({name:'loong'},function(err,doc){ doc.baseinfo.age=26; doc.save();});
 

你的問題應該是直接對文檔里的某一個內嵌文檔的屬性做修改,而不破壞整個文檔吧,我一般用原生的mongo-native,展示給你看下:

[root@centos6998 ~]# mongoMongoDB shell version:2.2.2 connecting to: test db.testcol.insert({info:{name:123,age:123,sex:"male"},id:1,weight:0})> db.testcol.find(){"_id":ObjectId("50de94734af5ea426ff2f77b"),"info":{"name":123,"age":123,"sex":"male"},"id":1,"weight":0}> db.testcol.update({id:1},{$set:{"info.name":0}})> db.testcol.find(){"_id":ObjectId("50de94734af5ea426ff2f77b"),"info":{"name":0,"age":123,"sex":"male"},"id":1,"weight":0}
 

@snoopy 吳哥的代碼形同我的代碼3,這個的確是可以,但是問題在於我上面提過的 1.需要將json嵌套轉換為字符串.連接格式 2.如果我要更新的數據比較多的時候,就要手動寫很多 按照你的例子,如果我要修改name和age,就要

db.testcol.update({id:1},{$set:{"info.name":0,"info.age":25}})//要將前端傳過來的json: {info:{name:0,age:25}} 轉換為{"info.name":0,"info.age":25}
 

火鉗劉明

 
var age, data, id, name; id = req.query.id; name = req.query.name; age = req.query.age; data ={ name:  name, age: age }; model.findOneAndUpdate({ _id: id }, data,null,function(err, results){if(err){return res.json(500, err);}#在此操作代碼});
 

用點語法,

//你的代碼1 schemaModel.update({name:'loong'},{$set:{"baseinfo.age":26}});//字段名加引號保險些,有時候不加引號會有問題,也搞不清楚什么時候有問題

另外再問你個問題啊,那個mongoose鏈接在整個項目里只可以有一個鏈接,那如果項目太大,進行數據操作的地方太多,那怎么辦,雖然schema什么的都可以在外面定義,但是db.once(“open”,function(){}),所有的數據操作都在回調里,那會很亂的吧。。。有什么比較官方的解決辦法嗎?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM