2016-07-07 175 views
0

我需要一些关于如何在MongoDB中复制一些SQL行为的帮助/建议。 具体来说,鉴于此集合:MongoDb聚合(SQL UNION风格)

{ 
    "_id" : ObjectId("577ebc0660084921141a7857"), 
    "tournament" : "Wimbledon", 
    "player1" : "Agassi", 
    "player2" : "Lendl", 
    "sets" : [{ 
     "score1" : 6, 
     "score2" : 4, 
     "tiebreak" : false 
    }, { 
     "score1" : 7, 
     "score2" : 6, 
     "tiebreak" : true 
    }, { 
     "score1" : 7, 
     "score2" : 6, 
     "tiebreak" : true 
    }] 
} 
{ 
    "_id" : ObjectId("577ebc3560084921141a7858"), 
    "tournament" : "Wimbledon", 
    "player1" : "Ivanisevic", 
    "player2" : "McEnroe", 
    "sets" : [{ 
     "score1" : 4, 
     "score2" : 6, 
     "tiebreak" : false 
    }, { 
     "score1" : 3, 
     "score2" : 6, 
     "tiebreak" : false 
    }, { 
     "score1" : 6, 
     "score2" : 4, 
     "tiebreak" : false 
    }] 
} 
{ 
    "_id" : ObjectId("577ebc7560084921141a7859"), 
    "tournament" : "Roland Garros", 
    "player1" : "Navratilova", 
    "player2" : "Graf", 
    "sets" : [{ 
     "score1" : 5, 
     "score2" : 7, 
     "tiebreak" : false 
    }, { 
     "score1" : 6, 
     "score2" : 3, 
     "tiebreak" : false 
    }, { 
     "score1" : 7, 
     "score2" : 7, 
     "tiebreak" : true 
    }, { 
     "score1" : 7, 
     "score2" : 5, 
     "tiebreak" : false 
    }] 
} 

而这两个不同的聚合:

1)聚合ALFA:这种聚合是故意奇怪,在这个意义上,它的目的是找到所有比赛,其中至少1场tiebreak为真只显示tiebreak为false的场数。请不要考虑它的逻辑,它是为了让用户完全自由而设计的。

{ 
    $match: { 
     "tournament": "Wimbledon", 
     "sets.tiebreak": true 
    } 
}, 
{ 
    $project: { 
     "tournament": 1, 
     "player1": 1, 
     "sets": { 
      $filter: { 
       input: "$sets", 
       as: "set", 
       cond: { 
        $eq: ["$$set.tiebreak", false] 
       } 
      } 
     } 
    } 
} 

2)聚合BETA:这种聚合是故意奇怪,在这个意义上,它的目的是找到所有的比赛,其中至少1抢七是假只显示集合,其中抢七是真的 。请不要考虑它的逻辑,它是为了让用户完全自由而设计的。请注意,player1对结果不了解。

{ 
    $match: { 
     "tournament": "Roland Garros", 
     "sets.tiebreak": false 
    } 
}, 
{ 
    $project: { 
     "tournament": 1, 
     "sets": { 
      $filter: { 
       input: "$sets", 
       as: "set", 
       cond: { 
        $eq: ["$$set.tiebreak", true] 
       } 
      } 
     } 
    } 
} 

现在假设这两个聚合目的是界定用户可以看到数据库的一部分,在这个意义上,这两个查询划定一切在对用户可见的文件(和细节)。这类似于用户有权访问的2个sql视图。

我需要/想要尝试重写以前的独特聚合只有一个。这可以实现吗?

它是强制性的,以保持聚合的&乙中设置的所有限制,而不丢失数据的任何控制和而不泄漏和数据,这不是在查询甲可用或B.

具体而言,在匹配只有当他们至少有一套以抢七结束时才能看到温网。玩家1字段可以看到。如果没有以tiebreak结尾并且以其他方式隐藏,则必须隐藏单个套。 如果需要,可以接受但不可取的是根本不会看到player1。

相反,只有当他们至少有一组没有平局休息时才能看到罗兰加洛斯的比赛。玩家1场必须隐藏。如果他们以tiebreak结束并且以其他方式隐藏,则必须看到单个组。

同样,目的是联合两个聚合,同时保持两个聚合强加的限制。

MongoDB是3.5版本,如果需要可以升级到unstable版本。

+0

在文本过滤器中使用正则表达式是额外的。以绩效为导向的战略是一个加,但不是强制性的。 – Manuele

+0

在我看来,你是从一个集合中提取数据,所以要获得这两种类型的数据试试$或。 UNION通常从具有相似列的不同表中抽取。 – Tiramisu

+0

是的,我从同一个集合拉...但不幸的是,点不在$匹配阶段(使用$或...),但$项目阶段,这似乎是不可能/太难我...谢谢无论如何! – Manuele

回答

0

这里是我的问题,两分钱:
如果你想避免空集时

  • 一个 “温布尔登” DOC具有所有true tibreaks,
  • 或“罗兰加洛斯“已有全部false抢七破

你可以重塑查询:

... 
{ 
    $and: [{ 
    "sets.tiebreak": true, 
    }, { 
    "sets.tiebreak": false 
    }], 
    $or: [{ 
    "tournament": "Wimbledon" 
    }, { 
    "tournament": "Roland Garros" 
    }] 
} 
... 

,并使用它:

+0

很难说哪一个是正确的行为,因为这只是一个测试。这一点是模仿SQL UNION。由于“Aggregation ALFA/BETA”会返回空集,我*认为*我的查询仍然是最正确的,但是您的注释指向的不是正确的注释。 这将是很好的基准两种不同的方法。我认为更多的阶段=更多的时间,但它也可能是一个* hard *投影可能会消耗比匹配/展开/匹配列表更多的时间...将调查... – Manuele

+0

我不会将您的答案标记为请在前面的评论中纠正原因,但这无疑是一种有效的方法。 – Manuele