使用pymongo和自定义_id字段进行Upsert

时间:2013-03-18 17:10:25

标签: mongodb pymongo

我正在尝试根据this document将预先汇总的效果指标存储在分片的mongodb中。

我正在尝试更新记录中的分钟子文档,这些子文档可能存在也可能不存在这样的upsert(self.collection是一个pymongo集合实例):

self.collection.update(query, data, upsert=True)

查询:

{   '_id': u'12345CHA-2RU020130304',
    'metadata': {   'adaptor_id': 'CHA-2RU',
                    'array_serial': 12345,
                    'date': datetime.datetime(2013, 3, 4, 0, 0, tzinfo=<UTC>),
                    'processor_id': 0}
}

数据:

{   'minute': {   '16': {   '45': 1.6693091}}}

问题是,在这种情况下,'minute'子文档始终只有最后hour: { minute: metric}条目,分钟子文档不会为其他小时创建新条目,它总是覆盖一个条目。

我还尝试使用$ set样式数据条目:

{ '$set': {   'minute': {   '16': {   '45': 1.6693091}}}}

但最终却是一样的。

我做错了什么?

2 个答案:

答案 0 :(得分:2)

在列出的两个示例中,您只需将字段('minute')设置为特定值,唯一的原因是它在您第一次更新时添加,因为字段本身不存在,因此必须被创造。

很难准确确定你在这里拍摄的内容,但我认为你可以做的是稍微改变你的模式,以便'minute'是一个数组。然后,您可以使用$push添加值,无论它们是否已存在,如果您不想要重复,也可以使用$addToSet

我必须稍微修改一下你的文档才能使它在shell中有效,所以我的_id(以及其他一些字段)与你的文档略有不同,但它仍然应该足够接近于说明:< / p>

db.foo.find({'_id': 'u12345CHA-2RU020130304'}).pretty()
{
        "_id" : "u12345CHA-2RU020130304",
        "metadata" : {
                "adaptor_id" : "CHA-2RU",
                "array_serial" : 12345,
                "date" : ISODate("2013-03-18T23:28:50.660Z"),
                "processor_id" : 0
        }
}

现在让我们添加一个minute字段,其中包含一系列文档而不是单个文档:

db.foo.update({'_id': 'u12345CHA-2RU020130304'}, { $addToSet : {'minute': { '16': {'45': 1.6693091}}}})
db.foo.find({'_id': 'u12345CHA-2RU020130304'}).pretty()
{
        "_id" : "u12345CHA-2RU020130304",
        "metadata" : {
                "adaptor_id" : "CHA-2RU",
                "array_serial" : 12345,
                "date" : ISODate("2013-03-18T23:28:50.660Z"),
                "processor_id" : 0
        },
        "minute" : [
                {
                        "16" : {
                                "45" : 1.6693091
                        }
                }
        ]
}

然后,为了说明添加,添加一个稍微不同的条目(因为我使用$addToSet这是添加新字段所必需的:

db.foo.update({'_id': 'u12345CHA-2RU020130304'}, { $addToSet : {'minute': { '17': {'48': 1.6693391}}}})
db.foo.find({'_id': 'u12345CHA-2RU020130304'}).pretty()
{
        "_id" : "u12345CHA-2RU020130304",
        "metadata" : {
                "adaptor_id" : "CHA-2RU",
                "array_serial" : 12345,
                "date" : ISODate("2013-03-18T23:28:50.660Z"),
                "processor_id" : 0
        },
        "minute" : [
                {
                        "16" : {
                                "45" : 1.6693091
                        }
                },
                {
                        "17" : {
                                "48" : 1.6693391
                        }
                }
        ]
}

答案 1 :(得分:2)

我最终设置了这样的字段:

查询:

{   '_id': u'12345CHA-2RU020130304',
    'metadata': {   'adaptor_id': 'CHA-2RU',
                    'array_serial': 12345,
                    'date': datetime.datetime(2013, 3, 4, 0, 0, tzinfo=<UTC>),
                    'processor_id': 0}
}

我正在设置这样的指标:

data = {"$set": {}}

for metric in csv:
  date_utc = metric['date'].astimezone(pytz.utc)
  data["$set"]["minute.%d.%d" % (date_utc.hour,
                                date_utc.minute)] = float(metric['metric'])

创建如下数据:

{"$set": {'minute.16.45': 1.6693091,
          'minute.16.46': 1.566343,
          'minute.16.47': 1.22322}}

因此,当self.collection.update(query, data, upsert=True)运行时,它会更新这些字段。