0

Eh bien, ceci est ma collectionréduisant la sortie du MongoDB en prenant derniers documents

{ 

"company" : "500010" 

"eqtcorp" : { 

    "306113" : { 
     "DATE" : "2014-05-05 16:43:00.000", 
     "subsection_name" : "CORPORATE NEWS", 
     "time" : "16:43" 
    }, 
    "306118" : { 
     "DATE" : "2014-05-08 16:43:00.000", 
     "subsection_name" : "CORPORATE NEWS", 
     "time" : "18:43" 
    }, 
    "306114" : { 
     "DATE" : "2014-06-02 16:43:00.000", 
     "subsection_name" : "CORPORATE NEWS", 
     "time" : "20:43" 
    } 
    "306116" : { 
     "DATE" : "2014-03-02 12:30:00.000", 
     "subsection_name" : "CORPORATE NEWS", 
     "time" : "20:43" 
    } 
    "306115" : { 
     "DATE" : "2014-08-02 04:45:00.000", 
     "subsection_name" : "CORPORATE NEWS", 
     "time" : "20:43" 
    } 
    "306117" : { 
     "DATE" : "2014-07-02 10:16:00.000", 
     "subsection_name" : "CORPORATE NEWS", 
     "time" : "20:43" 
    }     

    . 
    . 
    . 
    . 
    . 
      } 

} 

si je requête comme

db.collection_name.find({"company": "500010"}) 

je vais obtenir l'ensemble. Comme il y a beaucoup de sous-documents sous "eqtcorp", je n'ai besoin que de 3 sous-documents avec la date la plus récente. Simplement besoin d'un tri inverse sur la base du champ "DATE" dans tous les sous-documents sous "eqtcorp" et prendre le premier 3. C'est vraiment un défi puisque je suis nouveau avec Mongodb et mapreduce.

Ce que je me attends en sortie est

{ 

"company" : "500010" 

"eqtcorp" : {   

    "306113" : { 
     "DATE" : "2014-05-05 16:43:00.000", 
     "subsection_name" : "CORPORATE NEWS", 
     "time" : "16:43" 
    }, 
    "306118" : { 
     "DATE" : "2014-05-08 16:43:00.000", 
     "subsection_name" : "CORPORATE NEWS", 
     "time" : "18:43" 
    }, 

    "306116" : { 
     "DATE" : "2014-03-02 12:30:00.000", 
     "subsection_name" : "CORPORATE NEWS", 
     "time" : "20:43" 
    }    

      } 
} 

Tout tournage?

+0

où est « CORP »: venez « NIFTY » de dans le résultat? Est-ce que je manque quelque chose? Je ne le trouve pas dans le document original. –

+1

puisque vous ne voulez pas que toute la structure incorporée avec l'entreprise ne soit pas stockée de cette façon. Stockez un document pour chaque combinaison entreprise/date, indexez-le puis, lorsque vous recherchez une société, vous pouvez trier par date décroissante, limite (3) pour obtenir les trois plus récents. –

Répondre

1

si le sous-document "eqtcorp" est stocké sous forme de tableau comme mentionné ci-dessous

{ 
     "name" : "306113", // assigned it to a node to create an array 
     "DATE" : "2014-05-05 16:43:00.000", 
     "subsection_name" : "CORPORATE NEWS", 
     "time" : "16:43" 
    } 

Pour mettre à jour un seul document

db.collection_name.update(
     { company : "500010"}, 
     { $push : { 
      eqtcorp : { 
      $each: [ ], 
      $sort : { "DATE" : -1}, 
      $slice : 3 
     } 
    } 
}) 

Pour mettre à jour tous les documents

db.collection_name.update(
    {}, // query all documents 
    { 
    $push : { 
      eqtcorp : { 
       $each: [ ], 
       $sort : { "DATE" : -1}, 
       $slice : 3 
      } 
     } 
    }, 
    false, 
    true // update multiple documents 
) 
2

Il ya plusieurs choses qui ne vous aident pas vraiment ici, ce qui complique essentiellement ce qui est une opération par ailleurs simple.

Vous avez des dates qui sont réellement des chaînes que vous devriez vraiment changer pour être des types de date BSON appropriés. Il vous aidera plus tard où vous le voudrez probablement ainsi vous devriez les changer. Heureusement, ils ont au moins une portée lexicale par ordre de "AAAA-MM-JJ", donc ils vont trier, mais ne vous attendez pas à beaucoup d'autres utilisations sur eux.

Vous devriez également utiliser un tableau plutôt que d'imbriquer des sous-documents avec des clés. Ce sont vraiment difficiles à interroger car vous devez spécifier le chemin exact de l'élément. En tant que tel, vous êtes presque toujours limité au traitement JavaScript, qui est beaucoup plus lent que les alternatives. Je vais couvrir plus tard, mais passer:

vous pouvez aborder cela avec MapReduce est la suivante:

db.collection.mapReduce(
    function() { 
     for (var k in this.eqtcorp) { 
      this.eqtcorp[k].key = k; 
      emit(1, this.eqtcorp[k]); 
     } 
    }, 
    function (key,values) { 

     var reduced = {}; 

     values.sort(function(a,b) { 
      return ((a.DATE > b.DATE) ? -1 : ((a.DATE < b.DATE) ? 1 : 0)); 
     }).slice(-3).forEach(function(doc) { 
      reduced[doc.key] = doc; 
     }); 

     return reduced; 

    }, 
    { 
     "query": { "company": "50010" }, 
     "finalize": function(key,vaue) { 
      for (var k in value) { 
       delete value[k].key; 
      } 
      return value; 
     }, 
     "out": { "inline": 1 }, 
    }) 
) 

Dans le mappeur Je suis actuellement en utilisant une clé émise comme 1. La raison en est que la déclaration fonctionnerait pour "agréger" tous les résultats sur plusieurs documents. Mais si vous avez vraiment envie de le faire par votre valeur « société », alors vous pouvez émettre que la clé à la place, comme dans:

  emit(this.company, this.eqtcorp[k]); 

Essentiellement, le mappeur se désagréger chaque document juste sortie chaque sous-clé de "eqtcorp" comme son propre document. Ceux-ci sont ensuite transmis au réducteur. Le réducteur, qui peut être invoqué plusieurs fois, prend son tableau d'entrée de "valeurs" pour la même "clé" et les traite d'abord avec un sort sur ce tableau. Une fois triés (dans l'ordre croissant), vous devez ensuite ajouter les trois derniers éléments du tableau et ajouter chacun d'entre eux au résultat réduit.Comme je l'ai dit, le réducteur peut être invoqué plusieurs fois, de sorte que chaque passage n'obtient pas nécessairement la liste «entière» des valeurs par clé de regroupement. Ceci est la partie essentielle de la phase "réduire" en ce qu'elle prend "incrémentalement" chaque ensemble d'entrée et revient, en exécutant éventuellement la combinaison des résultats qui ont été réduits jusqu'à ce qu'il n'y ait qu'une seule valeur "clé" qui contient seulement les trois résultats vouloir.

Ensuite, il y a juste la fonction de finalisation qui nettoie une partie de l'entretien ménager qui a été fait pour simplifier le traitement du résultat par ses clés de sous-document d'origine. D'autres choses sont juste la requête de sélection et le choix de la sortie, qui selon vos besoins peuvent être à une autre collection. Ou bien, vous pouvez omettre la requête de sélection pour traiter tous les documents.


Comme indiqué précédemment, la structure du document n'aide pas et conviendrait mieux aux tableaux. Donc, vous devriez plutôt avoir un document comme celui-ci:

{ 

    "company" : "500010", 

    "eqtcorp" : [ 

     { 
      "key": "306113" 
      "DATE" : "2014-05-05 16:43:00.000", 
      "subsection_name" : "CORPORATE NEWS", 
      "time" : "16:43" 
     }, 
     { 
      "key": "306118", 
      "DATE" : "2014-05-08 16:43:00.000", 
      "subsection_name" : "CORPORATE NEWS", 
      "time" : "18:43" 
     }, 
     { 
      "key": "306114", 
      "DATE" : "2014-06-02 16:43:00.000", 
      "subsection_name" : "CORPORATE NEWS", 
      "time" : "20:43" 
     }, 
     { 
      "key:"306116", 
      "DATE" : "2014-03-02 12:30:00.000", 
      "subsection_name" : "CORPORATE NEWS", 
      "time" : "20:43" 
     }, 
     { 
      "key": "306115", 
      "DATE" : "2014-08-02 04:45:00.000", 
      "subsection_name" : "CORPORATE NEWS", 
      "time" : "20:43" 
     }, 
     { 
      "key": "306117", 
      "DATE" : "2014-07-02 10:16:00.000", 
      "subsection_name" : "CORPORATE NEWS", 
      "time" : "20:43" 
     }     
    ] 
} 

tout en laissant la seule date formats pour l'instant, cela rend les choses beaucoup plus propre que vous pouvez simplifier le traitement et même utiliser des choses comme le cadre d'agrégation pour le traitement beaucoup plus rapide si vous avaient l'intention de dire "trouver les trois meilleures valeurs" dans l'ensemble de la collection. Ce serait aussi simple que:

db.collection.aggregate([ 

    // Unwind the array 
    { "$unwind": "$eqtcorp" }, 

    // Sort the results by the dates 
    { "$sort": "eqtcorp.DATE" -1 }, 

    // Limit the top three results 
    { "$limit": 3 }, 

    // Optionally group back as an array 
    { "$group": { 
     "_id": null, 
     "eqtcorp": { "$push": "$eqtcorp" } 
    }} 

]) 

Ce serait pour toute la collection, obtenir les trois premiers par la valeur de l'entreprise est pas impossible, mais un peu plus impliqué car il n'y a pas d'équivalent de la tranche

db.collection.aggregate([ 

    // Unwind the array 
    { "$unwind": "$eqtcorp" }, 

    // Sort the results by company and date 
    { "$sort": "company": 1, "eqtcorp.DATE" -1 }, 

    // Group back keeping the top value 
    { "$group": { 
     "_id": "$company", 
     "all": { "$push": "$eqtcorp" }, 
     "one": { "$first": "$eqtcorp" } 
    }}, 

    // Unwind again 
    { "$unwind": "$all" }, 

    // match the "seen" value 
    { "$project": { 
     "all": 1, 
     "one": 1, 
     "seen": { 
      "$eq": [ "$all", "$one" ] 
     } 
    }}, 

    // Filter out "seen" 
    { "$match": { "seen": false } }, 

    // Group back keeping the new top 
    { "$group": { 
     "_id": "$_id", 
     "all": { "$push": "$all }, 
     "one": { "$first": "$one" }, 
     "two": { "$first": "$all } 
    }}, 

    // Unwind again 
    { "$unwind": "$all" }, 

    // Match the seen value 
    { "$project": { 
     "all": 1, 
     "one": 1, 
     "two": 1, 
     "seen": { 
      "$eq": [ "$all", "$two" ] 
     }  
    }}, 

    // Filter the seen value 
    { "$match": { "seen": false } }, 

    // Group back again 
    { "$group": { 
     "_id": "$_id", 
     "one": { "$first": "$one" }, 
     "two": { "$first": "$two }, 
     "three": { "$first": "$three" } 
    }} 
]) 

Ou modifier la carte ci-dessus réduisent au mappeur puisque nous sommes vraiment ne produit artificiellement le tableau:

function() { 
     this.eqtcorp.forEach(doc) { 
      emit(this.company, doc); 
     }); 
    } 

ce qui a encore un sens de diviser cette combinaison quand ke YS


Bien sûr, s'il n'y a pas d'agrégation réelle passe entre les documents et vous avez l'intention de base est d'obtenir que les trois dernières valeurs du tableau dans chaque document, l'approche claire est de les « trier » comme les documents sont mis à jour et les éléments sont ajoutés au tableau. Ainsi, votre approche pour ajouter de nouveaux éléments devient:

db.collection.update(
    { _id: document_id }, 
    { 
     "$push": { 
      "eqtcorp": { 
       "$each": [ { new document }, { optionally more} ], 
       "$sort": { "DATE": 1 } 
      } 
     } 
    } 
); 

Avant MongoDB 2.6 cela nécessite également un modificateur $slice qui imposerait essentiellement une limite supérieure du nombre d'éléments dans le tableau, mais ce n'est plus nécessaire. Avec les versions antérieures, vous devrez peut-être fournir une valeur limite supérieure, comme 500 ou un autre nombre supérieur à vos résultats attendus, sauf si vous vouliez réellement "élaguer" les résultats, auquel cas définissez vos limites.

Le point étant ici que sans agrégation passe alors quand vous voulez juste les trois dernières valeurs de ce tableau d'un document, vous faites juste cela avec la projection et l'opérateur $slice qui est disponible là:

db.collection.find({},{ "eqtcorp": { "$slice": -3 } }) 

Comme les éléments de tableau du document sont déjà triés, vous obtenez simplement les trois dernières valeurs, et vous avez terminé.


Alors, vraiment, alors que vous pouvez traiter votre document existant en utilisant MapReduce, sauf si vous voulez vraiment agréger les résultats, il est un processus beaucoup plus lent. Changer les données pour les tableaux et maintenir l'ordre de tri vous donnera immédiatement les résultats que vous voulez avec une requête très simple et rapide.

Même si votre intention est l'agrégation, les options disponibles lors de l'utilisation de tableaux sont beaucoup plus larges et il est généralement plus facile de faire des choses plus complexes.

0

Simplest Interrogation serait trier le tableau de sous-document basé sur la date et utiliser l'opérateur tranche pour obtenir les données nécessaires par projection

db.collection_name.find({"company": "500010"},{ "eqtcorp": { "$slice": -3 } }).sort({"eqtcorp.DATE":-1}) 
Questions connexes