2017-02-20 85 views
1

我一直無法進入我的MongoDB集合並更改複雜文檔中的值。我嘗試了比下面所示的一個例子更多的變化,各種變化,但都失敗了。MongoDB中複雜文檔update()的尋址問題是什麼?

我想將密鑰「空氣」的值從「雨」更改爲「清除」。在現實生活中,我不知道現在的關鍵「空氣」的價值是「下雨」。

請注意,我沒有使用MongoDB _id對象,並且希望在不使用它的情況下完成此操作。

3個文檔weatherSys集合中:

{ 
    "_id" : ObjectId("58a638fb1831c61917f921c5"), 
    "SanFrancisco" : [ 
     { "sky" : "grey" }, 
     { "air" : "rain" }, 
     { "ground" : "wet" } 
     ] 
    } 
    { 
    "_id" : ObjectId("58a638fb1831c61917f921c6"), 
    "LosAngeles" : [ 
     { "sky" : "grey" }, 
     { "air" : "rain" }, 
     { "ground" : "wet" } 
     ] 
    } 
    { 
    "_id" : ObjectId("58a638fb1831c61917f921c7"), 
    "SanDiego" : [ 
     { "sky" : "grey" }, 
     { "air" : "rain" }, 
     { "ground" : "wet" } 
     ] 
    } 

var docKey = "LosAngeles"; 
var subKey = "air"; 
var newValue = "clear"; 

var query  = {}; 
//var queryKey = docKey + ".$"; 
query[query] = subKey;     // query = { } 

var set  = {}; 
var setKey = docKey + ".0." + subKey; 
set[setKey] = newValue;      // set = { "weather.0.air" : "clear" } 

db.collection('weatherSys').update(query, { $set: set }, function(err, result) { 
    if (err) throw err; 
}); 

UPDATE-1: 好了,我希望我能找到一個佈局簡單一些比你建議,但我失敗了。我試過的所有東西都無法在「空氣」鍵級別上尋址。所以我複製並粘貼你的確切的JSON到我的收藏集並運行它。我使用MongoChef來操作和測試集合。

這是我的新佈局從粘貼在3倍的JSON掘進創建3個文件:

enter image description here

當我再嘗試更新的「舊金山」文檔的「空氣」鍵我有一個意外的結果。而不是更新的「空氣」:「幹」它開創了「舊金山」的對象一個新的「空氣」鍵:

enter image description here

所以我想好吧,讓我們重新嘗試更新,看看會發生什麼:

enter image description here

enter image description here

正如你可以看到它更新了它先前創建的 「空氣」 鍵。我打了這一點,並試圖使其工作「我」的方式,但我只是希望它的工作,所以我又重新在我的收藏佈局,沿着什麼是線「工作」:

enter image description here

而且再次運行更新:

enter image description here

然後我再次運行更新驗證:

enter image description here

它的工作原理,我在多文檔環境中正確更新。所以這是我當前的工作集佈局:

enter image description here

enter image description here

我有一個關於這個 -

  1. 我使用在頂級密鑰「天氣」幾個問題每份文件。它並沒有增加文件內的信息。是否有一個佈局設計更改,不需要密鑰和它帶來的開銷?

  2. 可以說我有使用「全天候」的關鍵。它的值是一個數組,但該數組只有一個元素,包含鍵的對象:城市,天空,空氣和地面。尋址是否需要僅使用一個元素的數組?或者我可以擺脫它。而不是「天氣」:[{}]設計可能是「天氣」:我還是會再次陷入非尋址問題?

  3. 看來我現在可以更新()鍵的任何值:空氣,天空和地面,但什麼是find()結構可以說讀取鍵的值「地面」的一個文件?

----> OK,我覺得我有這個問題#3- db.weatherSys.find({ 「weather.city」: 「舊金山」},{「weather.ground 「:1})

  1. 在您建議的原始集合佈局中,能否向我解釋爲什麼它沒有按照我們的預期更新,而是創建了一個新的「城市」對象?

這裏有很多。我感謝你堅持下去。

回答

1

您不能使用位置運算符通過其鍵查詢數組。

您可以通過索引訪問weather陣列,不過這意味着你知道數組索引。

例如,如果你想在weather陣列更新air元素值。

db.collection('weatherSys').update({}, { $set: { "weather.1.air" : "clear"} }); 

更新:

不幸的是,我看不到任何方式不知道key的數組索引更新值。

您不需要查詢對象,因爲您的密鑰是唯一的。

db.collection('weatherSys').update({}, { $set: { "SanFrancisco.1.air" : "clear"} }); 

如果你想確保鍵存在其它變型。

db.collection('weatherSys').update({ "SanFrancisco": { $exists: true } }, { $set: { "SanFrancisco.1.air" : "clear"} }); 

不知道你是否可以,但如果你可以更新你的結構到下面。

{ 
    "_id" : ObjectId("58a638fb1831c61917f921c5"), 
    "weather" : [ 
     { 
      "city": "LosAngeles", 
      "sky" : "grey" , 
      "air" : "rain" , 
      "ground" : "wet" 
     } 
    ] 
} 

您現在可以使用$positional運算符進行更新。

db.collection('weatherSys').update({"weather.city":"LosAngeles"}, { $set: { "weather.$.air" : "clear"} }); 

我利用一切文檔中的頂級鍵「天氣」。它不會對文檔中的信息增加 。有沒有佈局 設計更改,不需要該密鑰和 帶來的開銷?

我能想到的唯一佈局是將所有嵌入式屬性提升到頂層。對不起,不知道爲什麼我第一次沒有想到這件事。有時你只需要一個正確的問題來獲得正確的答案。

{ 
    "_id" : ObjectId("58a638fb1831c61917f921c5"), 
    "city": "LosAngeles", 
    "sky" : "grey", 
    "air" : "rain", 
    "ground" : "wet" 
} 

所有的更新將只是頂級更新。

db.collection('weatherSys').update({"city":"LosAngeles"}, { $set: { "air" : "clear"} }); 

可以說我有使用 「全天候」 的關鍵。它的值是一個數組,但 該數組只包含一個元素,該對象包含Keys, 城市,天空,空氣和地面。是否需要使用僅有一個元素的 陣列?或者我可以擺脫它。 「天氣」而不是 :[{}]設計可能是「天氣」:{}還是我會再次遇到 非尋址問題?

如果您對第一個建議沒有問題,則不適用。

看來現在我可以更新()的任何值的鑰匙:空氣, 天空,地面,但什麼是說讀取的 價值的關鍵「地」查找()結構在其中一個文件中?

db.weatherSys.find({ 「城市」: 「舊金山」},{ 「勤」:1})

在你所建議的原始集合的佈局,你能 向我解釋爲什麼它沒有按照我的預期更新,但 改爲創建了一個新的「城市」對象?

這是一個複製粘貼錯誤。我的意思是建議你現在的工作佈局。更新了我之前的佈局。

+0

非常有趣!你的代碼有效!但是我完全沒有期望查詢對象將是空的,所以我的例子顯然被修剪過了。環境由許多具有相同結構的文檔組成。我錯誤地認爲簡單更好。請問您是否再次查看它,因爲查詢的關鍵結構確實阻止了我訪問正確的文檔。謝謝。 – Ric

+0

更新答案根據您的更新添加選項。請驗證並讓我知道。 – Veeram

+0

有趣的想法,非常有幫助。讓我想想這個。我會回來的。 – Ric