2017-06-04 132 views
1

hotdeal:选择匹配阵列总

{ "property" : "ATL-D406" } 

翻译:

{ "property" : "ATL-D406", "language" : "gb", "txt": [{"aaa":"hi", "bbb":"bye"}] } 
{ "property" : "ATL-D406", "language" : "ru", "txt": [{"aaa":"priviet", "bbb":"baka"}] } 
{ "property" : "ATL-D406", "language" : "cn", "txt": [{"aaa":"??", "bbb":"??"}] } 

当前的结果:

{ "property":"ATL-D406", "language":[ "gb", "ru", "cn" ] } 

我想:

{ "property":"ATL-D406", "language":"gb", "aaa":"hi", "bbb":"bye" } 

我不明白为什么我的$ elemMatch不起作用,是不是应该将“转换”结果中的特定元素隔离开来?

也有一次,我只是采取“gb”语言,我怎么项目“aaa”和“bbb”没有他们在一个数组内?我尝试了$解决方案,但后来根本没有收到任何数据。你可以$解析数组中的数组吗? ($ resolve“txt”)?

db.hotdeal.aggregate([ 
    { '$match': {} }, 
    { '$lookup': { 
     from: 'translation', 
     localField: 'property', 
     foreignField: 'property', 
     as: 'translations' 
    } }, 

    { '$match': 
     { 'translations': 
      { '$elemMatch': { 'language': 'gb' } } 
     } 
    }, 

    { '$project': { 
     _id: 0, 
     property: 1, 
     language: '$translations.language' 
    }} 
]) 

回答

1

你做了错误的操作。你想看看$filter,$map,还有$arrayElemAt$elemMatch运算符是“数据选择”的“查询”操作,并且不用于“过滤”数组内容。

db.hotdeal.aggregate([ 
    { '$match': {} }, 
    { '$lookup': { 
     'from': 'translation', 
     'localField': 'property', 
     'foreignField': 'property', 
     'as': 'translations' 
    } }, 
    { '$project': { 
     '_id': 0, 
     'property': 1, 
     'translation': { 
     '$arrrayElemAt': [ 
      { '$map': { 
      'input': { 
       '$filter': { 
       'input': '$translations' 
       'as': 't', 
       'cond': { '$eq': [ '$$t.language', 'gb' ] } 
       }, 
      }, 
      'as': 't', 
      'in': { 
       'language': '$$t', 
       'aaa': { '$arrayElemAt': [ '$$t.txt.aaa', 0 ] }, 
       'bbb': { '$arrayElemAt': [ '$$t.txt.bbb', 0 ] } 
      } 
      }}, 
      0 
     ] 
     } 
    }}, 
    { '$project': { 
     'property': 1, 
     'language': '$translation.language', 
     'aaa': '$translation.aaa', 
     'bbb': '$translation.bbb' 
    }} 
]) 

我通常发现,这些排序“繁琐”结构性变化,最好在“客户端代码”来处理,而不是通过聚合框架重整反正。

所以根本就“加入”,然后让“客户”过程中的变化:

db.hotdeal.aggregate([ 
    { '$match': {} }, 
    { '$lookup': { 
     'from': 'translation', 
     'localField': 'property', 
     'foreignField': 'property', 
     'as': 'translations' 
    } } 
]).forEach(doc => { 
    let translation = doc.translations.find(t => t.language === 'gb'); 
    doc.language = translation.language; 
    doc.aaa = translation.txt[0].aaa; 
    doc.bbb = translation.txt[0].bbb; 

    delete doc.translations; 
    delete doc._id; 
    printjson(doc); 
}); 

这样做同样的事情,但远没有那么钝。

+0

嗨尼尔。有趣的,但一个相当复杂的方式来做到这一点。您确定您无法在$ match操作中使用$ elemMatch对从$查找中获取的数据进行操作吗?我相信我以前做过。 – torbenrudgaard

+0

@torbenrudgaard全部阅读。 '$ elemMatch'只会“确认”文档在'$ lookup'产生的数组元素中具有匹配的属性。它**不会删除它**。这就是你要问的。当你阅读所有内容时,我总结的是,“复杂”操作是完全不必要的。属于*类别下“只是因为你可以做到这一点,并不意味着你应该”*。 *瑞士军队电锯*以及所有这些。当你不是“聚合”时,不要过度使用聚合函数。 –

+0

尼尔,我只是设法这样做......呃!我无法在此格式化代码 - 让我将它作为答案发布,以便您可以看到它。 – torbenrudgaard

0
db.hotdeal.aggregate([ 
    { '$match': {} }, 
    { '$lookup': { 
     from: 'translation', 
     localField: 'property', 
     foreignField: 'property', 
     as: 'translations' 
    } }, 

    { '$unwind': '$translations' }, 

    { '$match': { 'translations.language': 'gb' } }, 

    { '$project': { 
     _id: 0, 
     property: 1, 
     language: '$translations.language', 
     aaa: '$translations.txt.aaa', 
     bbb: '$translations.txt.bbb' 
    }} 
])