1

如何查询与数组中对象的确切字段匹配的集合?

由于测试用例更明确,这里是要通过的测试。

a = Invitation.create(guests: [ Guest.new(player: 'bbb'), Guest.new(player: 'ccc') ])
b = Invitation.create(guests: [ Guest.new(player: 'ccc'), Guest.new(player: 'bbb') ])
c = Invitation.create(guests: [ Guest.new(player: 'bbb'), Guest.new(player: 'ccc'), Guest.new(player: 'ddd') ])

# Request to find invitation with bbb and ccc as player_id of guests, regardless the order.
result = Invitation.collection.find(...)
assert_equal result, [ a, b ]

我的用例是一个邀请系统,其中不存在相同的客人组合,因此当发送新邀请时,我需要检查是否有完全相同的客人(不管他们的顺序)。

注意:我使用一组 Guest 对象,因为它带有一些额外的数据。这是一个示例数据集(https://gist.github.com/anonymous/5507735)。

4

2 回答 2

1

也许$all是你需要的。我不确定您使用的是哪个 ORM 或什么模式,但这里有一个示例 mongo shell 输出:

> db.invitation.find({'guests.player':{'$all':['bbb','ccc']}})
{ "_id" : ObjectId("518319079468428b381d3563"), "guests" : [ { "player" : "bbb" }, { "player" : "ccc" } ] }
{ "_id" : ObjectId("518319239468428b381d3566"), "guests" : [ { "player" : "ccc" }, { "player" : "bbb" } ] }
{ "_id" : ObjectId("518319b39468428b381d3567"), "guests" : [ { "player" : "ccc" }, { "player" : "bbb" }, { "player" : "ddd" } ] }

如果您只想要那些包含'bbb''ccc'仅的,您可以尝试以下操作:

db.inv.find({'guests.player':{$all:['bbb','ccc']},
  'guests':{$not:{$elemMatch:{'player':{$nin:['bbb','ccc']}}}}})

这使:

[ 
  {   "_id" : ObjectId("518319079468428b381d3563"),
      "guests" : [ { "player" : "bbb" },   { "player" : "ccc" } ]   },
  {   "_id" : ObjectId("518319239468428b381d3566"),
      "guests" : [ { "player" : "ccc" },   { "player" : "bbb" } ]   }
]

如果你想要'bbb'and 'ccc',只需替换$all$in。这以某种方式是 XOR 实现,但我不确定它是否涵盖了您的所有用例。

于 2013-05-03T02:01:50.600 回答
1

基于 nyde1319 的回答;这感觉有点骇人听闻,但由于这里还没有其他答案:

db.invitation.find({'guests.player':{'$all':['bbb','ccc']}, guests: {$size: 2}})

当然,数字 2{$size: 2}取决于数组的长度。

于 2013-05-03T07:53:32.137 回答