2011-07-07 51 views
27

匹配非空文档我有一个集合正是如此结构:MongoDB的:在阵列

{ 
    _id: 1, 
    score: [ 
    { 
     foo: 'a', 
     bar: 0, 
     user: {user1: 0, user2: 7} 
    } 
    ] 
} 

我需要找到一个至少有一个“分数”(在得分数组元素)的所有文件具有一定的'bar'的值和一个非空'用户'子文档。

这是我想出了(它看起来喜欢它应该工作):

db.col.find({score: {"$elemMatch": {bar:0, user: {"$not":{}} }}}) 

但是,我得到这个错误:

error: { "$err" : "$not cannot be empty", "code" : 13030 } 

任何其他方式做到这一点?

+0

这是*究竟*它是如何构造的?似乎有点偏离。 **> v​​ar doc = {score:[foo:'a',bar:0,user:{user1:0,user2:7}]}; Thu Jul 7 00:43:42 SyntaxError:missing]在元素列表(shell)后面:1 ** –

+0

@Justin:你是对的,忘记了数组中的大括号。 – Dmitri

回答

51

想通了:{ 'score.user': { "$gt": {} } }将匹配非空文档。

+0

在这种情况下,'score.user'是一个对象。它是否也会检查数组“score”是否为空? – zVictor

+4

它可能,但对于数组,您可能最好使用:'{foo:{$ not:{$ size:0}}}' – Dmitri

+0

非常棒!我测试了,并且都工作。 你知道为什么第二种方法会更好吗? – zVictor

0

查看$ size操作符来检查数组大小。

+0

我没有检查任何数组的大小。我之前遗漏了一套大括号,现在可能会更清楚。一个等效的文件/对象操作符可以工作,但似乎并不存在。 – Dmitri

3

我不确定我是否理解你的模式,但也许最直接的方法是没有“空”值得分。用户

而不是故意而不是如果文档中没有内容,是否在该文档中包含该字段?

然后将查询可能是这样的......

> db.test.find({ "score" : { "$elemMatch" : { bar : 0, "user" : {"$exists": true }}}}) 

score.bar要(0在这种情况下)寻找一个值检查的MEAR存在($存在,see docsscore.user的(如果它有一个值,那么它会存在吗?)

editied:哎呀,我错过了$ elemMatch你有...

+1

是的,我想过这样做,我更喜欢一个匹配不存在和空'user'的查询的主要原因是个人用户分数可以被删除,我宁愿不必检查是否该subdoc是空的,需要每次删除。 – Dmitri

1

你可能想增加一个辅助阵列,用于跟踪用户的user文件:

{ 
    _id: 1, 
    score: [ 
    { 
     foo: 'a', 
     bar: 0, 
     users: ["user1", "user2"], 
     user: {user1: 0, user2: 7} 
    } 
    ] 
} 

然后你就可以原子添加新用户:

> db.test.update({_id: 1, score: { $elemMatch: {bar: 0}}},      
... {$set: {'score.$.user.user3': 10}, $addToSet: {'score.$.users': "user3"}}) 

删除用户:

> db.test.update({_id: 1, score: { $elemMatch: {bar: 0}}}, 
... {$unset: {'score.$.user.user3': 1}, $pop: {'score.$.users': "user3"}})  

查询成绩S:

> db.test.find({_id: 1, score: {$elemMatch: {bar: 0, users: {$not: {$size: 0}}}}}) 

如果你知道你将只添加不存在的用户,并从user文档中删除现存的用户,可以简化users到柜台,而不是一个数组,但上面是更有弹性。