鍍金池/ 問答/Python  數(shù)據(jù)庫/ pymongo聚合模塊 多條件、多表關(guān)聯(lián)、去重查詢

pymongo聚合模塊 多條件、多表關(guān)聯(lián)、去重查詢

問題描述

查詢7月1日注冊并充值的用戶。

相關(guān)代碼

8.3日更新:

# 獲取當月充值用戶
def get_registered_paying_user():
    unwind = {'$unwind': '$recharge'}                           # 付款拆分
    match1 = {'$match': {'regDate': regDate}}                   # 注冊日期
    match2 = {'$match': {'recharge.tradeNo': {'$ne': ''}}}      # 單號
    match3 = {'$match': {'recharge.rechargeDate': regDate}}     # 付款日期
    match4 = {'$match': {
                '$or': [
                    {'recharge.from': 'weixin'},                # 微信
                    {'recharge.from': 'alipay'}                 # 支付寶
                ]
             }}
    match5 = {'$match': {'recharge.real': {'$ne': 0}}}          # 付款金額
    lookup = {'$lookup':
        {
            'from': 'recharge',
            'localField': '_id',
            'foreignField': 'uid',
            'as': 'recharge'
        }
    }
    project = {'$project':
        {                                   # 顯示字段
            '_id': 1,                       # 用戶id
            'nickname': 1,                  # 用戶名
            'regDate': 1,                   # 注冊時間
            'recharge.tradeNo': 1,          # 單號
            'recharge.rechargeDate': 1,     # 付款日期
            'recharge.from': 1,             # 付款方式
            'recharge.real': 1              # 付款金額
        }
    }
    group = {'$group':
        {
            '_id': {
                '_id': '$_id',                                          # 用戶id
                'nickname': '$nickname',                                # 用戶名
                'regDate': '$regDate',                                  # 注冊時間
                'recharge.tradeNo': '$recharge.tradeNo',                # 單號
                'recharge.rechargeDate': '$recharge.rechargeDate',      # 付款日期
                'recharge.from': '$recharge.from',                      # 付款方式
                'recharge.real': '$recharge.real'                       # 付款金額
            },
        }
    }

    pipeline = [match1, lookup, unwind, project, match2, match3, match4, match5, group]
    result = collection_users.aggregate(pipeline)
    for i in result:
        pprint.pprint(i)

發(fā)現(xiàn)有個id重復的導致計數(shù)+1 如何避免這個問題呢?

{'_id': {'_id': ObjectId('5b5b035e1a620672c2438fa4'),
         'nickname': '渲客3947',
         'recharge.from': 'weixin',
         'recharge.real': 500,
         'recharge.rechargeDate': datetime.datetime(2018, 7, 28, 0, 16, 59, 418000),
         'recharge.tradeNo': '4200000145201807284145995390',
         'regDate': datetime.datetime(2018, 7, 27, 11, 34, 54, 113000)}}
{'_id': {'_id': ObjectId('5b5a65a21a620672c2438e3f'),
         'nickname': '渲客9528',
         'recharge.from': 'weixin',
         'recharge.real': 400,
         'recharge.rechargeDate': datetime.datetime(2018, 7, 27, 8, 28, 34, 458000),
         'recharge.tradeNo': '4200000154201807273809095287',
         'regDate': datetime.datetime(2018, 7, 27, 0, 21, 54, 837000)}}
{'_id': {'_id': ObjectId('5b5a65a21a620672c2438e3f'),
         'nickname': '渲客9528',
         'recharge.from': 'weixin',
         'recharge.real': 500,
         'recharge.rechargeDate': datetime.datetime(2018, 7, 27, 0, 39, 29, 708000),
         'recharge.tradeNo': '4200000145201807274527607790',
         'regDate': datetime.datetime(2018, 7, 27, 0, 21, 54, 837000)}}

原問題代碼

# 獲取當月充值用戶
def get_registered_paying_user():
    match1 = {'$match': {'regDate': regDate}}                   # 注冊日期
    match2 = {'$match': {'recharge.tradeNo': {'$ne': ''}}}      # 單號
    match3 = {'$match': {'recharge.rechargeDate': regDate}}     # 付款日期
    match4 = {'$match': {
                '$or': [
                    {'recharge.from': 'weixin'},                # 微信
                    {'recharge.from': 'alipay'}                 # 支付寶
                ]
             }}
    match5 = {'$match': {'recharge.real': {'$ne': 0}}}          # 付款金額
    lookup = {'$lookup':
        {
            'from': 'recharge',
            'localField': '_id',
            'foreignField': 'uid',
            'as': 'recharge'
        }
    }
    project = {'$project':
        {                                   # 顯示字段
            '_id': 1,                       # 用戶id
            'nickname':1,                   # 用戶名
            'regDate': 1,                   # 注冊時間
            'recharge.tradeNo': 1,          # 單號
            'recharge.rechargeDate': 1,     # 付款日期
            'recharge.from': 1,             # 付款方式
            'recharge.real': 1              # 付款金額
        }
    }

    pipeline = [match1, lookup, project, match2, match3, match4, match5]
    result = collection_users.aggregate(pipeline)

    for i in result:
        pprint.pprint(i)

get_registered_paying_user()

渲客2826 充值信息一個是注冊充值 一個是付費充值,但是付費充值不是7月1日當天的

{'_id': ObjectId('5b38335a1a620672c2435371'),
 'nickname': '渲客7128',
 'recharge': [{'from': 'regCoupon',
               'rechargeDate': datetime.datetime(2018, 7, 1, 1, 50, 23, 143000)},
              {'from': 'weixin',
               'real': 500,
               'rechargeDate': datetime.datetime(2018, 7, 1, 4, 31, 8, 191000),
               'tradeNo': '4200000157201807012108965206'}],
 'regDate': datetime.datetime(2018, 7, 1, 1, 50, 18, 382000)}
{'_id': ObjectId('5b3882541a620672930c532d'),
 'nickname': '渲客2826',
 'recharge': [{'from': 'regCoupon',
               'rechargeDate': datetime.datetime(2018, 7, 1, 7, 27, 26, 505000)},
              {'from': 'alipay',
               'real': 100,
               'rechargeDate': datetime.datetime(2018, 7, 28, 4, 29, 3, 50000),
               'tradeNo': '2018072821001004410593666887'}],
 'regDate': datetime.datetime(2018, 7, 1, 7, 27, 16, 701000)}
{'_id': ObjectId('5b38c69e1a620672c24354a8'),
 'nickname': '渲客3925',
 'recharge': [{'from': 'regCoupon',
               'rechargeDate': datetime.datetime(2018, 7, 1, 12, 18, 45, 846000)},
              {'from': 'alipay', 'real': 300},
              {'from': 'weixin',
               'real': 300,
               'rechargeDate': datetime.datetime(2018, 7, 2, 2, 11, 38, 284000),
               'tradeNo': '4200000150201807025314553741'}],
 'regDate': datetime.datetime(2018, 7, 1, 12, 18, 38, 859000)}
回答
編輯回答
逗婦乳

原因

$lookup 首先進行的是左外連接查詢。 當匹配到多個滿足外鍵條件的記錄時,會放到數(shù)組子集合里。 再之后你的match2,match3,match4,match5針對子集合查詢。 而mongo這里的子集合匹配,只要子集合中有一條滿足,就會全部整條記錄滿足。

解決方法

  1. 如果是mongodb V3.2、V3.4版本的$lookup提供的解決方案是先$unwind一下。
  2. 如果是mongodb V3.6及以上的版本,$lookup提供了pipeline字段。具體參考$lookup官方文檔
2018年9月8日 04:37
編輯回答
玩控
unwind = {'$unwind': '$recharge'}                           # 付款拆分
    match1 = {'$match': {'regDate': regDate}}                   # 注冊日期
    match2 = {'$match': {'recharge.tradeNo': {'$ne': ''}}}      # 單號
    match3 = {'$match': {'recharge.rechargeDate': regDate}}     # 付款日期
    match4 = {'$match': {
                '$or': [
                    {'recharge.from': 'weixin'},                # 微信
                    {'recharge.from': 'alipay'}                 # 支付寶
                ]
             }}
    match5 = {'$match': {'recharge.real': {'$ne': 0}}}          # 付款金額
    lookup = {'$lookup':
        {
            'from': 'recharge',
            'localField': '_id',
            'foreignField': 'uid',
            'as': 'recharge'
        }
    }
    project = {'$project':
        {                                   # 顯示字段
            '_id': 1,                       # 用戶id
            'nickname': 1,                  # 用戶名
            'regDate': 1,                   # 注冊時間
            'recharge.tradeNo': 1,          # 單號
            'recharge.rechargeDate': 1,     # 付款日期
            'recharge.from': 1,             # 付款方式
            'recharge.real': 1              # 付款金額
        }
    }
    group = {'$group':
        {
            '_id': {
                '_id': '$_id',                                          # 用戶id
                'nickname': '$nickname',                                # 用戶名
                'regDate': '$regDate',                                  # 注冊時間
            },
        }
    }

    pipeline = [match1, lookup, unwind, project, match2, match3, match4, match5, group]
    result = collection_users.aggregate(pipeline)
    a = 0
    for i in result:
        pprint.pprint(i)
        a = a + 1

    pprint.pprint('當月注冊并付費:' + str(a))
2017年4月18日 23:30