mongodb obtiene el documento/subdocumento que tiene el valor más alto

Tengo un comment colección como esta

{
  _id: 'c1',
  text: 'comment 1',
  votes: 1,
  replies: [
    {
      _id: 'r1',
      text: 'reply 1',
      isReply: true,
      votes: 3
    },
    {
      _id: 'r2',
      text: 'reply 2',
      isReply: true,
      votes: 0
    }
  ]
},
{
  _id: 'c2',
  text: 'comment2',
  votes: 2,
  replies: []
}

La idea es que un comentario puede tener muchas respuestas. Todos los comentarios y respuestas tienen id, texto, votos. ¿Cómo puedo obtener los mejores 2 comentarios o respuestas que tengan más votos. En el caso dado, será 'respuesta 1' y 'comentario 2'.

Puedo enviar 1 solicitud a mongodb para tener los mejores 2 comentarios y otra para tener las mejores 2 respuestas, luego compararlas para obtener lo que quiero.

Pero, ¿puede ser posible con solo 1 solicitud a mongodb, puedo tener un resultado como este?

 [
   {
     _id: 'r1',
     text: 'reply 1',
     isReply: true,
     votes: 3
   },
   {
     _id: 'c2',
     text: 'comment 2',
     votes: 2
   }
 ]

O mejor, ¿puedo aplanar el comentario/respuestas para tener una lista de comentarios o respuestas ordenados por votes? En este caso será [r1, c2, c1, r2] con sus respectivas propiedades

Gracias.


Actualización: lo intenté aggregate({$unwind: '$replies'}) pero todavía tengo comentarios y respuestas en 2 niveles diferentes que no puedo comparar usando el marco de agregación. Tal vez haya una manera de aplanar estos 2 niveles, soy muy nuevo en mongodb.

preguntado el 16 de septiembre de 13 a las 00:09

¿Podría editar su pregunta para incluir los detalles de las canalizaciones de agregación que ha probado? Me imagino que podría necesitar hacer algo como esto: docs.mongodb.org/manual/tutorial/… -

¿Necesitas todas las propiedades o solo su identificación y número de votos pueden ser suficientes? es decir, [{id:'r1',votos:X}, etc.]? -

@AsyaKamsky También necesito otras propiedades como se indica en el ejemplo de resultado. -

2 Respuestas

Un pequeño cambio en el esquema para desnormalizar los votos facilitaría la clasificación. Si hay otra serie de votos incrustados en el documento de comentarios, como:

votes: [ 
  { "type" : "c", "_id": "c1", v: 1},
  { "type" : "r", "_id": "r1", v: 3},
  { "type" : "r", "_id": "r2", v: 2}
]

consultar y clasificar podría ser sencillo.

db.playground.aggregate(
[
  {$project: { votes: 1 }},
  {$unwind: "$votes"},
  {$sort: {"votes.v": -1}},
  {$limit: 2}
])

Da el siguiente resultado.

{
  "result" : [
    {
      "_id" : "c1",
      "votes" : {
        "type" : "c",
        "_id" : "c1",
        "v" : 3
      }
    },
    {
      "_id" : "c1",
      "votes" : {
        "type" : "r",
        "_id" : "r1",
        "v" : 2
      }
    }
  ],
  "ok" : 1
}

Se necesita un índice en votes.v porque parece un caso de uso intensivo de lectura. Al actualizar los comentarios, simplemente actualice la matriz de votos en la misma solicitud de actualización.

Respondido el 20 de Septiembre de 13 a las 19:09

Si entiendo correctamente, esto es lo que harías, porque no puedo formatear el código en el comentario, creé una esencia de github aquí . No me parece sencillo solicitar los 2 mejores comentarios o respuestas. ¿Puedes darme un ejemplo por favor? - ultimo

@lastid, tu esencia me parece buena. Mejoré mi respuesta para dar un ejemplo de consulta de agregación. - visualzhou

Como se indica en mi pregunta y en mi esencia, necesito 2 mejores comentarios o respuestas con su contenido (texto). Con su solución, obtiene las mejores 2 identificaciones, luego de estas 2 identificaciones obtiene su contenido, ¿verdad? Por lo tanto, tendrá al menos 2 solicitudes, tal vez 3. Su estructura de datos también es complicada, si solo necesita 1 respuesta y su voto, debe obtener la respuesta de la matriz respuestas y también el votos propiedad, luego haga un ciclo para saber qué valor de votos es para la respuesta en cuestión. Una solución con 2 solicitudes que ya indiqué en mi pregunta, y preferí así porque votos es un vínculo a cada respuesta o comentario. - ultimo

Con respecto a la obtención de sus contenidos, sí, tienes razón. En realidad, su solución tiene mucho sentido, pero implica la fusión del lado del cliente. Ahora estamos hablando de la solución del lado de la base de datos. Mi primer pensamiento es tener votos en comentarios y respuestas y duplicarlos en otra matriz. Así que consultar una respuesta es como de costumbre. El problema principal es que le gustaría tratar los comentarios y las respuestas como si estuvieran en jerarquía al recuperarlos, y como el mismo tipo de cosas al votarlos. Así que el modelo de datos tiene que ser algo mixto. ¿Derecha? - visualzhou

Si los votos es lo que más te importa, haz reply como documento de nivel superior como comentarios y almacenar respuestas' _ids en una matriz en comment. Por lo tanto, obtener comentarios requiere dos solicitudes. Por cierto, no creo que haya una manera fácil de obtener solo un elemento en una matriz en un documento con su diseño actual, ya que el documento es la unidad básica de procesamiento. - visualzhou

Le sugiero que no ponga las respuestas en el objeto de comentario. DbObject tiene un tamaño máximo de 16 mb. Si un comentario obtuviera muchas respuestas, esta estructura fallaría. En lugar de esta estructura, puede mantener las respuestas en la colección de comentarios y colocar una identificación de comentario principal en el objeto de respuesta (es posible que desee colocar un campo como {tipo: 'respuesta'} o {tipo: 'comentario'} pero la existencia de parentCommentId proporcionará cuál es de qué tipo). De esta manera, puede consultar fácilmente tanto los comentarios como las respuestas.

También quiero agregar que las consultas de agregación no son buenas para la respuesta de la interfaz de usuario. No conozco tu caso de uso, pero no lo olvides.

Respondido el 16 de Septiembre de 13 a las 16:09

Si hago eso, me costará 2 consultas mostrar los primeros 10 comentarios y sus respuestas. Y luego, como estoy aprovechando la reactividad en Meteor, es más fácil para mí incrustar respuestas en cada comentario No sabía que las consultas de agregación son lentas... - ultimo

las consultas de agregación pueden o no ser lentas. depende de si hay índices para respaldarlos y cuánto trabajo están haciendo. - Asya Kamsky

Es lento para las acciones de la interfaz de usuario, agrupando espacialmente. - Mustafa Genç

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.