1

Ayant une liste de livres qui pointe vers une liste d'auteurs, je veux afficher un arbre, ayant dans chaque nœud le nom de l'auteur et le nombre de livres qu'il a écrit. Initialement, j'ai intégré le auteurs [] tableau directement dans livres collection, et cela a fonctionné comme un charme, en utilisant la magie du cadre d'agrégation. Cependant, plus tard, je me rends compte qu'il serait bon d'avoir des informations supplémentaires attachées à chaque auteur (par exemple, sa photo, ses données biographiques, sa date de naissance, etc.). Pour la première solution, cela est mauvais parce que:Comment compter des valeurs distinctes d'une collection de référence dans mongo

  • il fait double emploi avec les données (pas une grosse affaire, et oui, je sais que le but de mongo est d'encapsuler des objets pleins, mais Ignorons que pour l'instant);
  • lorsqu'une propriété supplémentaire est créée ou mise à jour sur les anciens enregistrements ne bénéficiera pas de cette modification, sauf si je demande spécifiquement une ancienne propriété unique et mettre à jour tous les auteurs de livres avec les nouvelles valeurs/mises à jour.

La prochaine chose était d'utiliser la deuxième collection, appelée auteurs, et chacun livres document faisant référence à une liste des ids de l'auteur, comme ceci:

{ 
    "_id" : ObjectId("58ed2a254374473fced950c1"), 
    "authors" : [ 
     "58ed2a254d74s73fced950c1", 
     "58ed2a234374473fce3950c1" 
    ], 
    "title" : "Book title" 
.... 
} 

Pour obtenir les détails de l'auteur , j'ai deux options:

  • faire une requête supplémentaire pour obtenir les données de l'auteur c ollection;
  • utilisez DBRefs.

Questions:

  1. Utilisation DBREFS charge automatiquement les données d'auteurs dans l'objet du livre, semblable à ce que JPA @MannyToOne fait par exemple?
  2. Est-il possible d'obtenir le nombre de livres écrits pour chaque auteur, sans avoir à demander le nombre de livres de chaque auteur? Lorsque les auteurs ont été intégrés, j'ai pu agréger le nom de l'auteur distinct et le nombre de documents de livres sur lesquels il était présent. Une telle requête est-elle possible entre deux collections?

Quelle serait votre recommandation pour l'implémentation de ce comportement? (J'utilise des données Spring)

+0

Pour 2 [recherche] (https: //docs.mongodb.com/manuel/référence/opérateur/agrégation/recherche /) aidera – Veeram

+0

J'ai été en mesure d'utiliser votre suggestion, merci beaucoup! Veuillez écrire une réponse afin que je puisse vous attribuer la réponse acceptée à ma question. Aussi, vous pourriez vouloir jeter un coup d'oeil à ma solution. Cela implique deux étapes: la première étape qui utilisera votre suggestion de recherche $ et la deuxième étape, une requête supplémentaire pour obtenir le nombre de livres sans auteurs, mais c'est parfaitement bien! Je craignais que je pourrais à 500 requêtes pour 500 auteurs, ce qui n'était pas acceptable. – hypercube

Répondre

2

Vous pouvez essayer la requête ci-dessous dans l'application spring mongo.

UnwindOperation unwindAuthorIds = Aggregation.unwind("authorsIds", true); 
LookupOperation lookupAuthor = Aggregation.lookup("authors_collection", "authorsIds", "_id", "ref"); 
UnwindOperation unwindRefs = Aggregation.unwind("ref", true); 
GroupOperation groupByAuthor = Aggregation.group("ref.authorName").count().as("count"); 

Aggregation aggregation = Aggregation.newAggregation(unwindAuthorIds, lookupAuthor, unwindRefs, groupByAuthor); 

List<BasicDBObject> results = mongoOperations.aggregate(aggregation, "book_collection", BasicDBObject.class).getMappedResults(); 
+0

Comme pour mongo 3.4+, il semble que le déroulement de la baie locale ne soit plus nécessaire, car montré ici https://jira.mongodb.org/browse/SERVER-22881. La ref se détendre était un bon truc si :). – hypercube

1

Suite @ suggestion de Veeram, j'ai pu écrire cette requête:

db.book_collection.aggregate([ 
    { 
     $unwind: "$authorsIds" 
    }, 
    { 
     $lookup: { 
      from: "authors_collection", 
      localField: "authorsIds", 
      foreignField: "_id", 
      as: "ref" 
     } 
    }, 
    {$group: {_id: "$ref.authorName", count: {$sum: 1}}} 
]) 

qui retourne quelque chose comme ceci:

{ 
    "_id" : [ 
     "Paulo Coelho" 
    ], 
    "count" : 1 
} 

/* 2 */ 
{ 
    "_id" : [ 
     "Jules Verne" 
    ], 
    "count" : 2 
} 

C'est exactement ce que je devais , et ça sonne à peu près juste. J'ai seulement besoin de faire une requête supplémentaire maintenant pour obtenir les livres sans ensemble d'auteurs.

+0

Vous n'avez pas besoin de seconde requête si vous utilisez '{$ unwind: {chemin:" $ authorIds ", preserveNullAndEmptyArrays: true}}' – Veeram