Метеор - опубликовать только счет для коллекции

Можно ли публиковать только счетчик для коллекции пользователю? Я хочу показать общее количество на главной странице, но не передавать все данные пользователю. Это то, что я пробовал, но он не работает:

Meteor.publish('task-count', function () {
    return Tasks.find().count();
});

this.route('home', { 
    path: '/',
    waitOn: function () {
        return Meteor.subscribe('task-count');
    }
});

Когда я пытаюсь это сделать, я получаю бесконечную анимацию загрузки.

Ответ 1

Meteor.publish функции должны возвращать курсоры, но здесь вы возвращаете непосредственно Number, который является общим количеством документов в вашей коллекции Tasks.

Подсчет документов в "Метеор" представляет собой удивительно сложную задачу, чем если бы вы хотели сделать это надлежащим образом: используя решение как элегантное, так и эффективное.

Пакет ros: publish-counts (вилка tmeasday: publish-counts) обеспечивает точный подсчет для небольших коллекций (100-1000) или "почти точный" счет для больших коллекций (десятки тысяч) с использованием опции fastCount.

Вы можете использовать его следующим образом:

// server-side publish (small collection)
Meteor.publish("tasks-count",function(){
  Counts.publish(this,"tasks-count",Tasks.find());
});

// server-side publish (large collection)
Meteor.publish("tasks-count",function(){
  Counts.publish(this,"tasks-count",Tasks.find(), {fastCount: true});
});

// client-side use
Template.myTemplate.helpers({
  tasksCount:function(){
    return Counts.get("tasks-count");
  }
});

Вы получите реактивный счет на стороне клиента, а также выполнимую реализацию на стороне сервера.

Эта проблема обсуждается в (оплачиваемом) проспекте Метеор, который рекомендуется прочитать: https://bulletproofmeteor.com/

Ответ 2

Я бы использовал Meteor.call

Клиент:

 var count; /// Global Client Variable

 Meteor.startup(function () {
    Meteor.call("count", function (error, result) {
      count = result;
    })
 });

return count в некотором вспомогательном

Сервер:

Meteor.methods({
   count: function () {
     return Tasks.find().count();
   }
})

* Обратите внимание, что это решение не будет реактивным. Однако, если желательна реакционная способность, она может быть включена.

Ответ 3

Это старый вопрос, но я надеюсь, что мой ответ может помочь тем, кому нужна эта информация, как и мне.

Иногда мне нужны разные, но реагирующие данные для отображения индикаторов в пользовательском интерфейсе, и хорошим примером является количество документов.

  1. Создайте повторно используемую (экспортированную) коллекцию только на стороне клиента, которая не будет импортирована на сервер (чтобы избежать создания ненужной коллекции базы данных). Обратите внимание на имя, переданное в качестве аргумента (здесь "misc").
import { Mongo } from "meteor/mongo";

const Misc = new Mongo.Collection("misc");

export default Misc;
  1. Создайте публикацию на сервере, которая принимает docId и имя key, где будет сохранен счет (со значением по умолчанию). Название коллекции для публикации это тот, который используется для создания коллекции только для клиентов ("misc"). Значение docId не имеет большого значения, оно просто должно быть уникальным среди всех документов Misc, чтобы избежать конфликтов. Подробнее о поведении публикации см. в Документах Meteor.
import { Meteor } from "meteor/meteor";
import { check } from "meteor/check";
import { Shifts } from "../../collections";

const COLL_NAME = "misc";

/* Publish the number of shifts that need revision in a 'misc' collection
 * to a document specified as 'docId' and optionally to a specified 'key'. */
Meteor.publish("shiftsToReviseCount", function({ docId, key = "count" }) {
  check(docId, String);
  check(key, String);

  let initialized = false;
  let count = 0;

  const observer = Shifts.find(
    { needsRevision: true },
    { fields: { _id: 1 } }
  ).observeChanges({
    added: () => {
      count += 1;

      if (initialized) {
        this.changed(COLL_NAME, docId, { [key]: count });
      }
    },

    removed: () => {
      count -= 1;
      this.changed(COLL_NAME, docId, { [key]: count });
    },
  });

  if (!initialized) {
    this.added(COLL_NAME, docId, { [key]: count });
    initialized = true;
  }

  this.ready();

  this.onStop(() => {
    observer.stop();
  });
});
  1. На клиенте импортируйте коллекцию, определите строку docId (можно сохранить в константе), подпишитесь на публикацию и получите соответствующий документ. Вуаля!
import { Meteor } from "meteor/meteor";
import { withTracker } from "meteor/react-meteor-data";
import Misc from "/collections/client/Misc";

const REVISION_COUNT_ID = "REVISION_COUNT_ID";

export default withTracker(() => {
  Meteor.subscribe("shiftsToReviseCount", {
    docId: REVISION_COUNT_ID,
  }).ready();

  const { count } = Misc.findOne(REVISION_COUNT_ID) || {};

  return { count };
});