2017-01-16 143 views
1

我使用了MongoDB几个月但基本用法,也许这是我第一次尝试使用更复杂的函数。在MongoDB中合并两个集合

我有两个类别:

集 '交易':

{ "_id" : ObjectId("5878ec66ad251f4fb4d2aacc"), "clubCode" : "43W0K", "date" : ISODate("2017-01-13T15:03:52.410Z"), "symbol" : "ENGI.PA", "name" : "ENGIE SA", "buyOrSell" : "buy", "orderDone" : true, "quantity" : 12, "price" : 11.99, "fees" : 0.99, "total" : 144.87, "__v" : 0 } 
{ "_id" : ObjectId("5878f8c339b47f0ee4a3b80b"), "clubCode" : "43W0K", "date" : ISODate("2017-01-13T15:56:32.088Z"), "symbol" : "PRIO.PA", "name" : "Lyxor ETF PEA Brazil (Ibovespa) C-EUR", "buyOrSell" : "buy", "orderDone" : true, "quantity" : 56, "price" : 8.92, "fees" : 0.99, "total" : 500.51, "__v" : 0 } 
{ "_id" : ObjectId("5878fadf39b47f0ee4a3b80c"), "clubCode" : "43W0K", "date" : ISODate("2017-01-13T16:05:35.849Z"), "symbol" : "ALVIV.PA", "name" : "Visiativ SA", "buyOrSell" : "buy", "orderDone" : true, "quantity" : 10, "price" : 18.15, "fees" : 0.99, "total" : 182.49, "__v" : 0 } 
{ "_id" : ObjectId("587a03319e3fe23138119937"), "clubCode" : "43W0K", "date" : ISODate("2017-01-14T10:52:56.208Z"), "symbol" : "BIG.PA", "name" : "BigBen Interactive", "buyOrSell" : "buy", "orderDone" : false, "orderType" : "ACL", "quantity" : 83, "price" : 6.01, "fees" : 0.99, "total" : 499.82, "__v" : 0 } 

收集 '订阅':

{ "_id" : ObjectId("587c946f3aa3f229a0922761"), "email" : "[email protected]", "clubCode" : "43W0K", "period" : ISODate("2016-09-01T22:00:00Z"), "amount" : 100, "type" : "recurrent", "__v" : 0 } 
{ "_id" : ObjectId("587c946f3aa3f229a0922762"), "email" : "[email protected]", "clubCode" : "43W0K", "period" : ISODate("2016-09-01T22:00:00Z"), "amount" : 100, "type" : "recurrent", "__v" : 0 } 
{ "_id" : ObjectId("587c946f3aa3f229a0922763"), "email" : "[email protected]", "clubCode" : "43W0K", "period" : ISODate("2016-09-01T22:00:00Z"), "amount" : 100, "type" : "recurrent", "__v" : 0 } 

每个都涉及到一个clubCode(这里 '43W0K')。

我想有这样的结果(在另一个集合,或只是一个汇总):

{ 
    clubCode: "43W0K", 
    treasury_moves: [ 
     { 
      date: ISODate("2017-01-13T15:03:52.410Z"), 
      wording: "Achat ENGIE SA", 
      amount: 144.87 
     }, { 
      date: ISODate("2017-01-13T15:56:32.088Z"), 
      wording: "Achat Lyxor ETF PEA Brazil (Ibovespa) C-EUR", 
      amount: 500.51 
     }, { 
      date: ISODate("2017-01-13T16:05:35.849Z"), 
      wording: "Achat Visiativ SA", 
      amount: 182.49 
     }, { 
      date: ISODate("2017-01-14T10:52:56.208Z"), 
      wording: "Achat BigBen Interactive", 
      amount: 499.82 
     }, { 
      date: ISODate("2016-09-01T22:00:00Z"), 
      wording: "Subscription [email protected]", 
      amount: 100 
     }, { 
      date: ISODate("2016-09-01T22:00:00Z"), 
      wording: "Subscription [email protected]", 
      amount: 100 
     }, { 
      date: ISODate("2016-09-01T22:00:00Z"), 
      wording: "Subscription [email protected]", 
      amount: 100 
     } 
    ] 
} 

所以之间的“交易”和“订阅”集合合并,

  • date等于'交易'的$date或'订阅'的$period
  • 其中wording等于Achat $name'交易'或Subscription $email的“订阅”
  • amount结果等于$total,如果它在“交易”,或者$amount如果它在“订阅”

首先,是有可能做到这一点?用mapreduce?聚合?

我期待着this topic这似乎相似,但我没有成功,我想要的结果。

如果您可以帮助我或只是指示我遵循的方式。

回答

1

可能通过aggregate()函数在聚合框架中。您需要运行下面的管道,以获得期望的结果:

db.trades.aggregate([ 
    { 
     "$lookup": { 
      "from": "subscriptions", 
      "localField": "clubCode", 
      "foreignField": "clubCode", 
      "as": "subs" 
     } 
    }, 
    { "$unwind": "$subs" }, 
    { 
     "$group": { 
      "_id": "$clubCode", 
      "trades": { 
       "$push": { 
        "date": "$date", 
        "wording": { "$concat": ["Achat ", "$name"] }, 
        "amount": "$total" 
       } 
      }, 
      "subs": { 
       "$push": { 
        "date": "$subs.period", 
        "wording": { "$concat": ["Subscription ", "$subs.email"] }, 
        "amount": "$subs.amount" 
       } 
      } 
     } 
    }, 
    { 
     "$project": { 
      "clubCode": "$_id", 
      "_id": 0, 
      "treasury_moves": { "$setUnion": ["$subs", "$trades"] } 
     } 
    } 
]) 

样本输出

/* 1 */ 
{ 
    "clubCode" : "43W0K", 
    "treasury_moves" : [ 
     { 
      "date" : ISODate("2017-01-13T15:03:52.410Z"), 
      "wording" : "Achat ENGIE SA", 
      "amount" : 144.87 
     }, 
     { 
      "date" : ISODate("2016-09-01T22:00:00.000Z"), 
      "wording" : "Subscription [email protected]", 
      "amount" : 100 
     }, 
     { 
      "date" : ISODate("2016-09-01T22:00:00.000Z"), 
      "wording" : "Subscription [email protected]", 
      "amount" : 100 
     }, 
     { 
      "date" : ISODate("2017-01-14T10:52:56.208Z"), 
      "wording" : "Achat BigBen Interactive", 
      "amount" : 499.82 
     }, 
     { 
      "date" : ISODate("2016-09-01T22:00:00.000Z"), 
      "wording" : "Subscription [email protected]", 
      "amount" : 100 
     }, 
     { 
      "date" : ISODate("2017-01-13T15:56:32.088Z"), 
      "wording" : "Achat Lyxor ETF PEA Brazil (Ibovespa) C-EUR", 
      "amount" : 500.51 
     }, 
     { 
      "date" : ISODate("2017-01-13T16:05:35.849Z"), 
      "wording" : "Achat Visiativ SA", 
      "amount" : 182.49 
     } 
    ] 
} 

在上面的管道,第一阶段包括$lookup运营商。这允许您对同一数据库中的其他集合执行“左外部联接”,以便从“已加入”集合中对文档进行筛选以进行处理。当您运行对trades收集管道与 只是这一步:

db.trades.aggregate([ 
    { 
     "$lookup": { 
      "from": "subscriptions", 
      "localField": "clubCode", 
      "foreignField": "clubCode", 
      "as": "subs" 
     } 
    } 
]) 

,你会得到以下结果:

/* 1 */ 
{ 
    "_id" : ObjectId("5878ec66ad251f4fb4d2aacc"), 
    "clubCode" : "43W0K", 
    "date" : ISODate("2017-01-13T15:03:52.410Z"), 
    "symbol" : "ENGI.PA", 
    "name" : "ENGIE SA", 
    "buyOrSell" : "buy", 
    "orderDone" : true, 
    "quantity" : 12, 
    "price" : 11.99, 
    "fees" : 0.99, 
    "total" : 144.87, 
    "__v" : 0, 
    "subs" : [ 
     { 
      "_id" : ObjectId("587c946f3aa3f229a0922761"), 
      "email" : "[email protected]", 
      "clubCode" : "43W0K", 
      "period" : ISODate("2016-09-01T22:00:00.000Z"), 
      "amount" : 100, 
      "type" : "recurrent", 
      "__v" : 0 
     }, 
     { 
      "_id" : ObjectId("587c946f3aa3f229a0922762"), 
      "email" : "[email protected]", 
      "clubCode" : "43W0K", 
      "period" : ISODate("2016-09-01T22:00:00.000Z"), 
      "amount" : 100, 
      "type" : "recurrent", 
      "__v" : 0 
     }, 
     { 
      "_id" : ObjectId("587c946f3aa3f229a0922763"), 
      "email" : "[email protected]", 
      "clubCode" : "43W0K", 
      "period" : ISODate("2016-09-01T22:00:00.000Z"), 
      "amount" : 100, 
      "type" : "recurrent", 
      "__v" : 0 
     } 
    ] 
} 

/* 2 */ 
{ 
    "_id" : ObjectId("5878f8c339b47f0ee4a3b80b"), 
    "clubCode" : "43W0K", 
    "date" : ISODate("2017-01-13T15:56:32.088Z"), 
    "symbol" : "PRIO.PA", 
    "name" : "Lyxor ETF PEA Brazil (Ibovespa) C-EUR", 
    "buyOrSell" : "buy", 
    "orderDone" : true, 
    "quantity" : 56, 
    "price" : 8.92, 
    "fees" : 0.99, 
    "total" : 500.51, 
    "__v" : 0, 
    "subs" : [ 
     { 
      "_id" : ObjectId("587c946f3aa3f229a0922761"), 
      "email" : "[email protected]", 
      "clubCode" : "43W0K", 
      "period" : ISODate("2016-09-01T22:00:00.000Z"), 
      "amount" : 100, 
      "type" : "recurrent", 
      "__v" : 0 
     }, 
     { 
      "_id" : ObjectId("587c946f3aa3f229a0922762"), 
      "email" : "[email protected]", 
      "clubCode" : "43W0K", 
      "period" : ISODate("2016-09-01T22:00:00.000Z"), 
      "amount" : 100, 
      "type" : "recurrent", 
      "__v" : 0 
     }, 
     { 
      "_id" : ObjectId("587c946f3aa3f229a0922763"), 
      "email" : "[email protected]", 
      "clubCode" : "43W0K", 
      "period" : ISODate("2016-09-01T22:00:00.000Z"), 
      "amount" : 100, 
      "type" : "recurrent", 
      "__v" : 0 
     } 
    ] 
} 

/* 3 */ 
{ 
    "_id" : ObjectId("5878fadf39b47f0ee4a3b80c"), 
    "clubCode" : "43W0K", 
    "date" : ISODate("2017-01-13T16:05:35.849Z"), 
    "symbol" : "ALVIV.PA", 
    "name" : "Visiativ SA", 
    "buyOrSell" : "buy", 
    "orderDone" : true, 
    "quantity" : 10, 
    "price" : 18.15, 
    "fees" : 0.99, 
    "total" : 182.49, 
    "__v" : 0, 
    "subs" : [ 
     { 
      "_id" : ObjectId("587c946f3aa3f229a0922761"), 
      "email" : "[email protected]", 
      "clubCode" : "43W0K", 
      "period" : ISODate("2016-09-01T22:00:00.000Z"), 
      "amount" : 100, 
      "type" : "recurrent", 
      "__v" : 0 
     }, 
     { 
      "_id" : ObjectId("587c946f3aa3f229a0922762"), 
      "email" : "[email protected]", 
      "clubCode" : "43W0K", 
      "period" : ISODate("2016-09-01T22:00:00.000Z"), 
      "amount" : 100, 
      "type" : "recurrent", 
      "__v" : 0 
     }, 
     { 
      "_id" : ObjectId("587c946f3aa3f229a0922763"), 
      "email" : "[email protected]", 
      "clubCode" : "43W0K", 
      "period" : ISODate("2016-09-01T22:00:00.000Z"), 
      "amount" : 100, 
      "type" : "recurrent", 
      "__v" : 0 
     } 
    ] 
} 

/* 4 */ 
{ 
    "_id" : ObjectId("587a03319e3fe23138119937"), 
    "clubCode" : "43W0K", 
    "date" : ISODate("2017-01-14T10:52:56.208Z"), 
    "symbol" : "BIG.PA", 
    "name" : "BigBen Interactive", 
    "buyOrSell" : "buy", 
    "orderDone" : false, 
    "orderType" : "ACL", 
    "quantity" : 83, 
    "price" : 6.01, 
    "fees" : 0.99, 
    "total" : 499.82, 
    "__v" : 0, 
    "subs" : [ 
     { 
      "_id" : ObjectId("587c946f3aa3f229a0922761"), 
      "email" : "[email protected]", 
      "clubCode" : "43W0K", 
      "period" : ISODate("2016-09-01T22:00:00.000Z"), 
      "amount" : 100, 
      "type" : "recurrent", 
      "__v" : 0 
     }, 
     { 
      "_id" : ObjectId("587c946f3aa3f229a0922762"), 
      "email" : "[email protected]", 
      "clubCode" : "43W0K", 
      "period" : ISODate("2016-09-01T22:00:00.000Z"), 
      "amount" : 100, 
      "type" : "recurrent", 
      "__v" : 0 
     }, 
     { 
      "_id" : ObjectId("587c946f3aa3f229a0922763"), 
      "email" : "[email protected]", 
      "clubCode" : "43W0K", 
      "period" : ISODate("2016-09-01T22:00:00.000Z"), 
      "amount" : 100, 
      "type" : "recurrent", 
      "__v" : 0 
     } 
    ] 
} 

在接下来的步骤中,您将需要拼合具有$unwind的子阵列用于处理作为您的下一个流水线阶段:

db.trades.aggregate([ 
    { 
     "$lookup": { 
      "from": "subscriptions", 
      "localField": "clubCode", 
      "foreignField": "clubCode", 
      "as": "subs" 
     } 
    }, 
    { "$unwind": "$subs" } 
]) 

这将产生i x j文档,其中i是原始集合(4)中的文档数量,而j是数组元素数量(3)。


下一步,$group,然后将组中的12份文件由clubCode字段,并创建两个阵列与来自字段中指定的子文档:在管道

db.trades.aggregate([ 
    { 
     "$lookup": { 
      "from": "subscriptions", 
      "localField": "clubCode", 
      "foreignField": "clubCode", 
      "as": "subs" 
     } 
    }, 
    { "$unwind": "$subs" }, 
    { 
     "$group": { 
      "_id": "$clubCode", 
      "trades": { 
       "$push": { 
        "date": "$date", 
        "wording": { "$concat": ["Achat ", "$name"] }, 
        "amount": "$total" 
       } 
      }, 
      "subs": { 
       "$push": { 
        "date": "$subs.period", 
        "wording": { "$concat": ["Subscription ", "$subs.email"] }, 
        "amount": "$subs.amount" 
       } 
      } 
     } 
    } 
]) 

输出

/* 1 */ 
{ 
    "_id" : "43W0K", 
    "trades" : [ 
     { 
      "date" : ISODate("2017-01-13T15:03:52.410Z"), 
      "wording" : "Achat ENGIE SA", 
      "amount" : 144.87 
     }, 
     { 
      "date" : ISODate("2017-01-13T15:03:52.410Z"), 
      "wording" : "Achat ENGIE SA", 
      "amount" : 144.87 
     }, 
     { 
      "date" : ISODate("2017-01-13T15:03:52.410Z"), 
      "wording" : "Achat ENGIE SA", 
      "amount" : 144.87 
     }, 
     { 
      "date" : ISODate("2017-01-13T15:56:32.088Z"), 
      "wording" : "Achat Lyxor ETF PEA Brazil (Ibovespa) C-EUR", 
      "amount" : 500.51 
     }, 
     { 
      "date" : ISODate("2017-01-13T15:56:32.088Z"), 
      "wording" : "Achat Lyxor ETF PEA Brazil (Ibovespa) C-EUR", 
      "amount" : 500.51 
     }, 
     { 
      "date" : ISODate("2017-01-13T15:56:32.088Z"), 
      "wording" : "Achat Lyxor ETF PEA Brazil (Ibovespa) C-EUR", 
      "amount" : 500.51 
     }, 
     { 
      "date" : ISODate("2017-01-13T16:05:35.849Z"), 
      "wording" : "Achat Visiativ SA", 
      "amount" : 182.49 
     }, 
     { 
      "date" : ISODate("2017-01-13T16:05:35.849Z"), 
      "wording" : "Achat Visiativ SA", 
      "amount" : 182.49 
     }, 
     { 
      "date" : ISODate("2017-01-13T16:05:35.849Z"), 
      "wording" : "Achat Visiativ SA", 
      "amount" : 182.49 
     }, 
     { 
      "date" : ISODate("2017-01-14T10:52:56.208Z"), 
      "wording" : "Achat BigBen Interactive", 
      "amount" : 499.82 
     }, 
     { 
      "date" : ISODate("2017-01-14T10:52:56.208Z"), 
      "wording" : "Achat BigBen Interactive", 
      "amount" : 499.82 
     }, 
     { 
      "date" : ISODate("2017-01-14T10:52:56.208Z"), 
      "wording" : "Achat BigBen Interactive", 
      "amount" : 499.82 
     } 
    ], 
    "subs" : [ 
     { 
      "date" : ISODate("2016-09-01T22:00:00.000Z"), 
      "wording" : "Subscription [email protected]", 
      "amount" : 100 
     }, 
     { 
      "date" : ISODate("2016-09-01T22:00:00.000Z"), 
      "wording" : "Subscription [email protected]", 
      "amount" : 100 
     }, 
     { 
      "date" : ISODate("2016-09-01T22:00:00.000Z"), 
      "wording" : "Subscription [email protected]", 
      "amount" : 100 
     }, 
     { 
      "date" : ISODate("2016-09-01T22:00:00.000Z"), 
      "wording" : "Subscription [email protected]", 
      "amount" : 100 
     }, 
     { 
      "date" : ISODate("2016-09-01T22:00:00.000Z"), 
      "wording" : "Subscription [email protected]", 
      "amount" : 100 
     }, 
     { 
      "date" : ISODate("2016-09-01T22:00:00.000Z"), 
      "wording" : "Subscription [email protected]", 
      "amount" : 100 
     }, 
     { 
      "date" : ISODate("2016-09-01T22:00:00.000Z"), 
      "wording" : "Subscription [email protected]", 
      "amount" : 100 
     }, 
     { 
      "date" : ISODate("2016-09-01T22:00:00.000Z"), 
      "wording" : "Subscription [email protected]", 
      "amount" : 100 
     }, 
     { 
      "date" : ISODate("2016-09-01T22:00:00.000Z"), 
      "wording" : "Subscription [email protected]", 
      "amount" : 100 
     }, 
     { 
      "date" : ISODate("2016-09-01T22:00:00.000Z"), 
      "wording" : "Subscription [email protected]", 
      "amount" : 100 
     }, 
     { 
      "date" : ISODate("2016-09-01T22:00:00.000Z"), 
      "wording" : "Subscription [email protected]", 
      "amount" : 100 
     }, 
     { 
      "date" : ISODate("2016-09-01T22:00:00.000Z"), 
      "wording" : "Subscription [email protected]", 
      "amount" : 100 
     } 
    ] 
} 

您需要与$setUnion运营商加入两个数组,而忽略重复在您的最终聚合管道,$project。这也将重塑文档,将_id密钥替换为clubCode字段。运行这些阶段的最终管道将为您提供理想的结果。

+1

哇,令人印象深刻!非常感谢,它工作得很好,我现在明白了(呃...我相信... :))一切的工作! 再次感谢! – Toma

+0

不用担心,总是乐意帮助:)如果您需要对管道进行进一步的说明,请随时在评论中给我留言。 – chridam

+0

现在,没有关于你给我什么的其他问题。 只是另一件事,我想按日期排序结果。我试图在流水线中添加“排序”,但我没有成功对它们进行排序。 我试图把'{$ sort:{treasury_moves.date:1}}'放在'$ project'之后,但它不起作用。 如果我把它放在$ unwind之后,我可以对每个集合进行排序,但不能放在一起。 你有任何解决方案吗? 谢谢! :) – Toma