How to publish a view/transform of a collection in Meteor?

為{幸葍}努か 提交于 2019-12-17 10:49:28

问题


I have made a collection

var Words = new Meteor.Collection("words");

and published it:

Meteor.publish("words", function() {
    return Words.find();
});

so that I can access it on the client. Problem is, this collection is going to get very large and I just want to publish a transform of it. For example, let's say I want to publish a summary called "num words by length", which is an array of ints, where the index is the length of a word and the item is the number of words of that length. So

wordsByLength[5] = 12;

means that there are 12 words of length 5. In SQL terms, it's a simple GROUP BY/COUNT over the original data set. I'm trying to make a template on the client that will say something like

  • You have N words of length X

for each length. My question boils down to "I have my data in form A, and I want to publish a transformed version, B".


回答1:


UPDATE You can transform a collection on the server like this:

Words = new Mongo.Collection("collection_name"); 

Meteor.publish("yourRecordSet", function() {

  //Transform function
  var transform = function(doc) {
    doc.date = new Date();
    return doc;
  }

  var self = this;

  var observer = Words.find().observe({
      added: function (document) {
      self.added('collection_name', document._id, transform(document));
    },
    changed: function (newDocument, oldDocument) {
      self.changed('collection_name', oldDocument._id, transform(newDocument));
    },
    removed: function (oldDocument) {
      self.removed('collection_name', oldDocument._id);
    }
  });

  self.onStop(function () {
    observer.stop();
  });

  self.ready();

});



回答2:


To wrap transformations mentioned in other answers, you could use the package I developed, meteor-middleware. It provides a nice pluggable API for this. So instead of just providing a transform, you can stack them one on another. This allows for code reuse, permissions checks (like removing or aggregating fields based on permissions), etc. So you could create a class which allows you to aggregate documents in the way you want.

But for your particular case you might want to look into MongoDB aggregation pipeline. If there is really a lot of words you probably do not want to transfer all of them from the MongoDB server to the Meteor server side. On the other hand, aggregation pipeline lacks the reactivity you might want to have. So that published documents change counts as words come in and go.

To address that you could use another package I developed, PeerDB. It allows you to specify triggers which would be reactively called as data changes, and stored in the database. Then you could simply use normal publishing to send counts to the client. The downside is that all users should be interested in the same collection. It works globally, not per user. But if you are interested in counts of words per whole collection, you could do something like (in CoffeesScript):

class WordCounts extends Document
  @Meta
    name: 'WordCounts'

class Words extends Document
  @Meta
    name: 'Words'
    triggers: =>
      countWords: @Trigger ['word'], (newDocument, oldDocument) ->
        # Document has been removed.
        if not newDocument._id
          WordCounts.update
            length: oldDocument.word.length
          ,
            $inc:
              count: -1
        # Document has been added.
        else if not oldDocument._id
          WordCounts.update
            length: newDocument.word.length
          ,
            $inc:
              count: 1
        # Word length has changed.
        else if newDocument.word.length isnt oldDocument.word.length
          WordCounts.update
            length: oldDocument.word.length
          ,
            $inc:
              count: -1
          WordCounts.update
            length: newDocument.word.length
          ,
            $inc:
              count: 1

And then you could simply publish WordCounts documents:

Meteor.publish 'counts', ->
  WordCounts.documents.find()



回答3:


You could assemble the counts by going through each document in Words, (cursor for each)

var countingCursor = Words.find({});
var wordCounts = {};

countingCursor.forEach(function (word) {
  wordCounts[word.length].count += 1;
  wordCounts[word.length].words = wordCounts[word.length].words || []
  wordCounts[word.length].words.push(word);
});

create a local collection,

var counts = new Meteor.Collection('local-counts-collection', {connection: null});

and insert your answers

var key, value;

for (key in wordCounts) {
  value = object[key];
  counts.insert({
    length: key,
    count: value.count,
    members: value.words
  });
}

Counts is now a collection, just not stored in Mongo.

Not tested!



来源:https://stackoverflow.com/questions/18343534/how-to-publish-a-view-transform-of-a-collection-in-meteor

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!