2011-07-07 22 views
27

Tengo una colección estructurada de esta manera:MongoDB: coincidir con el doc no vacío en orden

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

Tengo que encontrar todos los documentos que tienen al menos una 'puntuación' (elemento de la matriz de puntuación) que tiene una cierta valor de 'bar' y un subdocumento 'usuario' no vacío.

Esto es lo que ocurrió con (y parecía que debería funcionar):

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

Pero, me sale este error:

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

Cualquier otra manera de hacer esto?

+0

¿Es eso * exactamente * cómo está estructurado? Parece un poco apagado. **> var doc = {puntaje: [foo: 'a', barra: 0, usuario: {usuario1: 0, usuario2: 7}]}; Jue Jul 7 00:43:42 SintaxisError: falta] después de la lista de elementos (shell): 1 ** –

+0

@Justin: tienes razón, olvidé las llaves dentro de la matriz. – Dmitri

Respuesta

51

Calculado: { 'score.user': { "$gt": {} } } coincidirá con documentos no vacíos.

+0

En este caso, 'score.user' es un objeto. ¿También funcionaría comprobar si 'score', una matriz, está vacía? – zVictor

+4

Podría, pero para las matrices es probable que sea mejor utilizar: '{foo: {$ no: {$ tamaño: 0}}}' – Dmitri

+0

¡excelente! Probé y ambos funcionaron. ¿Sabes por qué la segunda opción sería mejor? – zVictor

0

Mire el operador $ size para comprobar los tamaños de matriz.

+0

No estoy verificando el tamaño de ninguna matriz. Dejé un par de llaves antes, puede ser más claro ahora. Un operador equivalente para documentos/objetos funcionaría, pero eso no parece existir. – Dmitri

3

No estoy seguro de entender bastante su esquema, pero quizás la manera más directa sería no tener un valor "vacío" para score.user?

En lugar de eso intencionalmente no ¿Tiene ese campo en su documento si no tiene contenido?

A continuación, la consulta podría ser algo así como ...

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

es decir, buscar un valor en score.bar que desea (0 en este caso) la comprobación de la existencia Mear ($ existe, see docs) de score.user (y si tiene un valor, entonces va a existir?)

editied: oops me perdí la elemMatch $ tenías ...

+1

Sí, he pensado en hacerlo de esa manera, la razón principal por la que preferiría una consulta que coincida con el 'usuario' inexistente y vacío es que los puntajes de usuario individuales se pueden eliminar y prefiero no tener que verificar si el subdoc está vacío y debe eliminarse cada vez. – Dmitri

1

Es posible que desee agregar una matriz auxiliar que realiza un seguimiento de los usuarios en el user documento:

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

continuación, puede añadir nuevos usuarios atómicamente :

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

eliminar usuarios:

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

puntuación de consultas s:

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

Si sabes que sólo le añade usuarios no existentes y eliminar los usuarios existentes del documento user, puede simplificar users a un contador en lugar de una matriz, pero lo anterior es más resistente.

Cuestiones relacionadas