1

我无法访问我的 MongoDB 集合并更改复杂文档中的值。我尝试了比下面显示的一个示例更多的变体,各种变体,但都失败了。

我想将键“air”的值从“rain”更改为“clear”。在现实生活中,我不会知道“空气”键的当前值是“雨”。

请注意,我没有使用 MongoDB _id 对象,并且想在不使用它的情况下完成此操作。

weatherSys 集合中的 3 个文档:

    {
    "_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 个文档:

在此处输入图像描述

然后,当我尝试更新“旧金山”文档的“空气”键时,我得到了意想不到的结果。它没有更新 "air":"dry",而是在 "San Francisco" 对象中创建了一个新的 "air" 键:

在此处输入图像描述

所以我想好吧,让我们再次尝试更新,看看会发生什么:

在此处输入图像描述

在此处输入图像描述

如您所见,它更新了之前创建的“air”键。我可以解决这个问题并尝试让它以“我的”方式工作,但我只是想让它工作,所以我再次重新配置我的收藏布局,按照“工作”的方式:

在此处输入图像描述

并再次运行更新:

在此处输入图像描述

然后我通过再次运行更新来验证它:

在此处输入图像描述

它有效,我在多文档环境中正确更新。所以这是我当前的工作集合布局:

在此处输入图像描述

在此处输入图像描述

我对此有几个问题-

  1. 我在每个文档中都使用顶级键“天气”。它不会向文档中的信息添加任何内容。是否存在不需要该键及其带来的开销的布局设计更改?

  2. 可以说我必须使用“天气”键。它的值是一个数组,但该数组只有一个元素,即包含键的对象:城市、天空、空气和地面。寻址是否需要使用只有一个元素的数组?或者我可以摆脱它。而不是 "weather":[{}] 设计可以是 "weather":{} 还是我会再次遇到不可寻址问题?

  3. 看来我现在可以 update() 键的任何值:空气、天空和地面,但是 find() 结构是什么来读取其中一个文档中的键“地面”的值?

----> 好的,我想我有这个问题 #3- db.weatherSys.find({ "weather.city" : "San Francisco" }, { "weather.ground": 1 })

  1. 在您建议的原始集合布局中,您能否向我解释为什么它没有像您和我预期的那样更新,而是创建了一个新的“城市”对象?

这里很多。我很感激你坚持下去。

4

1 回答 1

1

您不能使用位置运算符通过其键查询数组。

您可以weather按索引访问数组,但这意味着您知道数组索引。

例如,如果您想更新数组air中的元素值weather

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

更新:

不幸的是,在不知道键的数组索引的情况下,我看不到任何更新值的方法。

您不需要查询对象,因为您的键是唯一的。

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"} } );

可以说我必须使用“天气”键。它的值是一个数组,但该数组只有一个元素,即包含键的对象:城市、天空、空气和地面。寻址是否需要使用只有一个元素的数组?或者我可以摆脱它。而不是 "weather":[{}] 设计可以是 "weather":{} 还是我会再次遇到不可寻址问题?

如果您同意第一个建议,则不适用。

看来我现在可以 update() 键的任何值:空气、天空和地面,但是 find() 结构是什么,在其中一个文档中读取键“地面”的值?

db.weatherSys.find({ "city" : "San Francisco" }, { "ground": 1 })

在您建议的原始集合布局中,您能否向我解释为什么它没有像您和我预期的那样更新,而是创建了一个新的“城市”对象?

那是复制粘贴错误。我的意思是建议您现在拥有的工作布局。更新了我之前的布局。

于 2017-02-20T02:29:24.650 回答