Hi, 各位
又来请教问题了,这次是 update 操作合并的问题.
首先给一个简化版的文档数据如下:
{ "_id" : "8qwsax", "sys_cpu_user": 2, "sys_cpu_idle": 40, "sys_network_traffic" : [ { "device" : "eth0", "type" : "rx", "value" : 1231231 }, { "device" : "eth0", "type" : "tx", "value" : 1235 }, { "device" : "eth1", "type" : "rx", "value" : 1231231 }, { "device" : "eth1", "type" : "tx", "value" : 1235 } ]}
目前计划使用 mongodb 存储监控数据的最新状态, 由于服务器数量较多, 每个监控数据 update 一次数据库是无法接受的(理论每分钟100W条监控数据), 所以理所当然的想到了将多个监控数据合并起来写的问题.
比如 sys_cpu_user 和 sys_cpu_idle 这两个监控数据可以通过如下一条命令写入:
db.datapoint.update({'_id': '8qwsax'}, {'$set': {'sys_cpu_user': 3, 'sys_cpu_idle': 22}})
类似 sys_network_traffic 这种 array 数据, 针对每个 elem 的 update 操作是不支持 upsert 的, 比如下面的语句是行不通的:
db.datapoint.update({'_id': '8qwsax', 'sys_network_traffic': {'$elemMatch': {'device': 'eth0', 'type': 'rx'}}}}, {'$set': {'sys_network_traffic.$.value': 1000}}, upsert=True)
因为 upsert 这个参数和 array 的 $ 相冲突, 这个操作必须拆分成先 pull 再 push(upsert 模式).
上面全是废话, 正题来了.....
前面的 set 操作可以简单的合并起来, 但是 pull 操作如何合并写呢?
开始我简单的以为应该这么写:
db.datapoint.update({'_id': '8qwsax'}, {'$pull': {'sys_network_traffic': [{'device': 'eth0', 'type': 'tx'}, {'device': 'eth0', 'type': 'rx'}]}})
不行, 然后我又猜测应该这么写:
db.datapoint.update({'_id': '8qwsax'}, {'$pull': {'sys_network_traffic': {'$in': [{'device': 'eth0', 'type': 'tx'}, {'device': 'eth0', 'type': 'rx'}]}}})
不行, 然后我又猜测应该这么写:
db.datapoint.update({'_id': '8qwsax'}, {'$pull': {'sys_network_traffic': {'$elemMatch': {'$in': [{'device': 'eth0', 'type': 'rx'}, {'device': 'eth0', 'type': 'tx'}]}}}})
还是不行.....看官方的文档也没见有更新同一 array 下多个 elem 的例子, 都是更新不同 array(多个_id)下相同 elem 的例子
作为新手表示无能为力了,各位大神求帮忙?
第 1 条附言 · 2015-05-27 10:35:30 +08:00
昨晚又查了查相关的文档, 发现用如下方法是可以删除多个 elem 的:
db.datapoint.update({'_id': '8qwsax'}, {'$pullAll': {'sys_network_traffic': [{'device': 'eth0', 'type': 'rx', 'value': 1231231}, {'device': 'eth0', 'type': ‘tx’, ‘value’: 1235}]}})
但是现在有个问题是在我做这个更新操作时, 是不知道每个 elem 里 value 这个字段的值.
只知道 device 和 type 这两个字段, 并且通过这两个字段可以确定到唯一的 elem 上
- -@
第 2 条附言 · 2015-05-27 14:32:04 +08:00
db.datapoint.update({'_id': '8qwsax'}, {'$pull': {'sys_network_traffic': {'$or': [{'device': 'eth0', 'type': 'rx'}, {'device': 'eth0', 'type': 'tx'}]}}})
终于搞定了, 忘记了 $or 这个操作...