MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Grupuj według wartości i warunków

Aby wykonać jakiekolwiek „grupowanie” z zapytaniami MongoDB, chcesz mieć możliwość korzystania z platformy agregacji lub mapReduce. Struktura agregacji jest ogólnie preferowana, ponieważ używa natywnych operatorów kodowanych zamiast tłumaczenia JavaScript, a zatem jest zazwyczaj szybsza.

Instrukcje agregacji można uruchamiać tylko po stronie interfejsu API serwera, co ma sens, ponieważ nie chcesz tego robić na kliencie. Ale można to zrobić tam i udostępnić wyniki klientowi.

Z przypisaniem tej odpowiedzi za dostarczenie metod publikowania wyników:

Meteor.publish("cardLikesDislikes", function(args) {
    var sub = this;

    var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;

    var pipeline = [
        { "$group": {
            "_id": "$card_id",
            "likes": {
                "$sum": {
                    "$cond": [
                        { "$eq": [ "$vote", 1 ] },
                        1,
                        0
                    ]
                }
            },
            "dislikes": {
                "$sum": {
                    "$cond": [
                        { "$eq": [ "$vote", 2 ] },
                        1,
                        0
                    ]
                }
            },
            "total": {
                "$sum": {
                    "$cond": [
                        { "$eq": [ "$vote", 1 ] },
                        1,
                        -1
                    ]
                }
            }
        }},
        { "$sort": { "total": -1 } }
    ];

    db.collection("server_collection_name").aggregate(        
        pipeline,
        // Need to wrap the callback so it gets called in a Fiber.
        Meteor.bindEnvironment(
            function(err, result) {
                // Add each of the results to the subscription.
                _.each(result, function(e) {
                    // Generate a random disposable id for aggregated documents
                    sub.added("client_collection_name", Random.id(), {
                        card: e._id,                        
                        likes: e.likes,
                        dislikes: e.dislikes,
                        total: e.total
                    });
                });
                sub.ready();
            },
            function(error) {
                Meteor._debug( "Error doing aggregation: " + error);
            }
        )
    );

});

Ogólna instrukcja agregacji to tylko $group operacja na pojedynczym kluczu "card_id". Aby uzyskać „polubienia” i „nielubienia”, użyj „wyrażenia warunkowego”, którym jest $cond .

Jest to operator „trójargumentowy”, który uwzględnia test logiczny na wartości „głosowania” i tam, gdzie pasuje do oczekiwanego typu, wówczas dodatnie 1 jest zwracany, w przeciwnym razie jest to 0 .

Wartości te są następnie wysyłane do akumulatora, którym jest $sum aby dodać je razem i uzyskać łączną liczbę dla każdego „card_id” jako „lubię” lub „nie lubię”.

W przypadku „suma” najskuteczniejszym sposobem jest przypisanie „pozytywnej” wartości „lubię” i ujemnej wartości „nie lubię” w tym samym czasie, co grupowanie. Istnieje $add operatora, ale w tym przypadku jego użycie wymagałoby kolejnego etapu potoku. Więc zamiast tego robimy to na jednym etapie.

Na końcu znajduje się $sort w porządku malejącym, więc największe liczby pozytywnych głosów są na górze. Jest to opcjonalne i możesz po prostu użyć strony klienta sortowania dynamicznego. Ale to dobry początek dla ustawienia domyślnego, które eliminuje konieczność zrobienia tego.

A więc to jest agregacja warunkowa i praca z wynikami.

Lista testowa

To właśnie przetestowałem z nowo utworzonym projektem meteor, bez dodatków i tylko z jednym szablonem i plikiem javascript

polecenia konsoli

meteor create cardtest
cd cardtest
meteor remove autopublish

Utworzono kolekcję "karty" w bazie z dokumentami zamieszczonymi w pytaniu. A następnie edytowałem domyślne pliki o poniższej zawartości:

cardtest.js

Cards = new Meteor.Collection("cardStore");

if (Meteor.isClient) {

  Meteor.subscribe("cards");

  Template.body.helpers({
    cards: function() {
      return Cards.find({});
    }
  });

}

if (Meteor.isServer) {

  Meteor.publish("cards",function(args) {
    var sub = this;

    var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;

    var pipeline = [
      { "$group": {
        "_id": "$card_id",
        "likes": { "$sum": { "$cond": [{ "$eq": [ "$vote", 1 ] },1,0] } },
        "dislikes": { "$sum": { "$cond": [{ "$eq": [ "$vote", 2 ] },1,0] } },
        "total": { "$sum": { "$cond": [{ "$eq": [ "$vote", 1 ] },1,-1] } }
      }},
      { "$sort": { "total": -1, "_id": 1 } }

    ];

    db.collection("cards").aggregate(
      pipeline,
      Meteor.bindEnvironment(
        function(err,result) {
          _.each(result,function(e) {
            e.card_id = e._id;
            delete e._id;

            sub.added("cardStore",Random.id(), e);
          });
          sub.ready();
        },
        function(error) {
          Meteor._debug( "error running: " + error);
        }
      )
    );

  });
}

cardtest.html

<head>
  <title>cardtest</title>
</head>

<body>
  <h1>Card aggregation</h1>

  <table border="1">
    <tr>
      <th>Card_id</th>
      <th>Likes</th>
      <th>Dislikes</th>
      <th>Total</th>
    </tr>
    {{#each cards}}
      {{> card }}
    {{/each}}
  </table>

</body>

<template name="card">
  <tr>
    <td>{{card_id}}</td>
    <td>{{likes}}</td>
    <td>{{dislikes}}</td>
    <td>{{total}}</td>
  </tr>
</template>

Ostateczna zagregowana treść kolekcji:

[
   {
     "_id":"Z9cg2p2vQExmCRLoM",
     "likes":3,
     "dislikes":1,
     "total":2,
     "card_id":1
   },
   {
     "_id":"KQWCS8pHHYEbiwzBA",
      "likes":2,
      "dislikes":0,
      "total":2,
      "card_id":2
   },
   {
      "_id":"KbGnfh3Lqcmjow3WN",
      "likes":1,
      "dislikes":0,
      "total":1,
      "card_id":3
   }
]


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. ScaleGrid ogłasza usługi hostingowe MongoDB w Kanadzie

  2. MongoDB $dayOfYear

  3. Nodejs / Express — uruchamianie mojej aplikacji:express.createServer() jest przestarzałe

  4. Mongo Query pytanie $gt,$lt

  5. serwer zwrócił błąd na etapie uwierzytelniania SASL:Uwierzytelnianie nie powiodło się