V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐工具
RoboMongo
推荐书目
50 Tips and Tricks for MongoDB Developers
Related Blogs
Snail in a Turtleneck
ry_wang
V2EX  ›  MongoDB

Array update 操作合并的问题

  •  
  •   ry_wang · 2015-05-26 17:06:24 +08:00 · 3666 次点击
    这是一个创建于 3469 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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 这个操作...
    1 条回复    2015-06-19 16:40:38 +08:00
    jiangzhuo
        1
    jiangzhuo  
       2015-06-19 16:40:38 +08:00
    頻繁改變Array的大小而沒有實現進行相應的優化就比較作死了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2697 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 09:57 · PVG 17:57 · LAX 01:57 · JFK 04:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.