【问题标题】:Combining nested collection in mongodb with documents written from parallel nodes将 mongodb 中的嵌套集合与从并行节点写入的文档相结合
【发布时间】:2015-02-07 15:52:18
【问题描述】:

我正在考虑是否可以使用 MongoDB 来帮助解决我们的存储和处理问题。这个想法是计算将以多处理方式在每个节点上完成,并使用唯一的 mongodb ObjectId 写入 mongodb。字典中的数据结构如下:

{a: {b: {c: [100, 200, 300]} }

a、b 和 c 是整数键

当计算完成并将所有记录写入 mongo 时,必须组合文档,以便我们按顶层 a 分组,然后按 b 分组,然后按 c 分组。所以两个文档可能包含(Example A):

document1:{24: {67: {12: [100, 200]}}}

文档2:{24: {68: {12: [100, 200]}}}

那么如果我们结合:

合并:{24: {67: {12: [100, 200]}, 68: [100, 200]}}

如果我们还有另外几个文档(ExampleB):

document1:{24: {67: {12: [100, 200]}}}

文档2:{24: {67: {12: [300, 400]}}}

合并:{24: {67: {12: [100, 200, 300, 400]}}}

结合这些嵌套结构的最佳方法是什么。我可以手动遍历每个文档并在 python 中执行此操作,但是有更聪明的方法吗?我需要保留底层数据结构。

【问题讨论】:

  • mongodb 中的$push 指令不能为您解决这个问题吗?
  • 为什么不使用 map reduce?动态键使聚合结果变得更加困难。
  • @AlexLaties,我想将这些 $push 作为批处理作业,并且由于数据结构的原因,想知道它是否太复杂。

标签: python mongodb pymongo


【解决方案1】:

以@chapelo 为基础:

##Import python mongodb API:
import pymongo

##Build aggregation framework:
def aggregate(documents, base_document=None, unique=True):
    # use unique=False to keep all values in the lists, even if repeated
    # like [100, 100, 200, 300], leave it True otherwise
    for doc in documents:
        if isinstance(doc, list):
            if base_document is None: base_document = []
            for d in doc:
                base_document.append(d)
            if unique==True: base_document = set(base_document)
            base_document = sorted(base_document)
        else:
            if base_document is None: base_document = {}
            for d in doc:
                b = base_document[d] if d in base_document \
                    else [] if isinstance(doc[d], list) else {}
                base_document[d] = aggregate([doc[d]], base_document=b)
    return base_document

##Open mongodb connection:
db = pymongo.MongoClient()

##Query old documents without ObjectIds:
old_dict = db.old.collection.find({},{"_id":0})

##Run old documents through aggregation framework:
new_dict =  aggregate(old_dict)

##Insert aggregated documents into new mongodb collection:
for i in new_dict:
   db.new.collection.insert({i:new_dict[i]})

##Close mongodb connection:
db.close()

【讨论】:

    【解决方案2】:

    用 python 进行聚合有什么不聪明的地方?考虑以下函数:

    def aggregate(documents, base_document=None, unique=True):
        # use unique=False to keep all values in the lists, even if repeated
        # like [100, 100, 200, 300], leave it True otherwise
        for doc in documents:
            if isinstance(doc, list):
                if base_document is None: base_document = []
                for d in doc:
                    base_document.append(d)
                if unique==True: base_document = set(base_document)
                base_document = sorted(base_document)
            else:
                if base_document is None: base_document = {}
                for d in doc:
                    b = base_document[d] if d in base_document \
                        else [] if isinstance(doc[d], list) else {}
                    base_document[d] = aggregate([doc[d]], base_document=b)
        return base_document
    

    使用以下文档集进行测试,它产生了聚合:

    documents = [   {20: {55: { 7: [100, 200]}}},
                    {20: {68: {12: [100, 200]}}},
                    {20: {68: {12: [500, 200]}}},
                    {23: {67: {12: [100, 200]}}},
                    {23: {68: {12: [100, 200]}}},
                    {24: {67: {12: [300, 400]}}},
                    {24: {67: {12: [100, 200]}}},
                    {24: {67: {12: [100, 200]}}},
                    {24: {67: {12: [300, 500]}}},
                    {24: {67: {13: [600, 400]}}},
                    {24: {67: {13: [700, 900]}}},
                    {24: {68: {12: [100, 200]}}},
                    {25: {67: {12: [100, 200]}}},
                    {25: {67: {12: [300, 400]}}},   ]
    
    from pprint import pprint
    pprint(aggregate(documents))
    
    ''' 
    {20: {55: {7: [100, 200]}, 68: {12: [100, 200, 500]}},
     23: {67: {12: [100, 200]}, 68: {12: [100, 200]}},
     24: {67: {12: [100, 200, 300, 400, 500], 13: [400, 600, 700, 900]},
          68: {12: [100, 200]}},
     25: {67: {12: [100, 200, 300, 400]}}}
    '''
    

    【讨论】:

    • 差不多了,但是仍然需要有许多文档以第一个 id 为键,所以它看起来像 {24: {..}, 20:{..}}
    • @Navonod 我不明白您在评论中的观点,您能否向我解释一下,也许指出所获得的答案有什么问题。我编辑了答案,结果字典更清楚
    猜你喜欢
    • 1970-01-01
    • 2018-01-26
    • 2019-02-16
    • 2020-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-01
    • 1970-01-01
    相关资源
    最近更新 更多