0

I have two collections: Commands and CommandHistory. I am trying to make an output that received the results of both of them, combined, where anything from CommandHistory is bold. That is, something that looked like:

**Do the thing**    <--| **Command History*
Doing thing           <-|
thing is in progress  <-| Commands
thing is done         <-|
**Do the other thing**             <-| **Command History**
I don't know what the other thing is <-| Commands

Here is a basic start of a helper:

log() {
  const commandCursor = Commands.find({}, { sort: { timestamp: 1 } });
  const commandHistory = CommandHistory.find({}, { sort: { timestamp: 1 } });
  // what now? Need to concatenate them.
  // `.fetch()` makes the interface seem non-reactive.
}

The only thing I can really think of is to make yet another (null) collection and output everything from both collections into it, which seems like overkill.

Is it possible to concatenate the results of these two cursors, and still have it act reactively?

corvid
  • 10,733
  • 11
  • 61
  • 130
  • Is there a key that relates `Commands` to `CommandHistory`? It looks like there are several of the former for every one of the latter. – Michel Floyd Mar 29 '16 at 16:00
  • CommandHistory is added to whenever they submit a form and contains the values of that form. After it has been successfully submitted, it runs the command via a Meteor method – corvid Mar 29 '16 at 16:43
  • So there is a key relationship between the two collections? – Michel Floyd Mar 29 '16 at 17:12
  • not really, one would look like `{ commands: 'MESSAGE "hello"', timestamp: ISODATE() }` and one would look like `{ message: "Hello", timestamp: ISODATE }` – corvid Mar 29 '16 at 17:17

1 Answers1

1

I think what you are looking for is mainly a way to combine both result sets. For that, you could use something like this:

log: function () {
        var commands = Commands.find({}, { sort: { timestamp: 1 } }).map(function(i){i.origin='command'; return i;});
      var history  = History.find({}, { sort: { timestamp: 1} }).map(function(i){i.origin='history'; return i;});
      var combined = _.union(commands, history);
      return _.sortBy(combined, function(i) { return Number(i.timestamp) });
    }

Here I'm adding a field called "origin" to identify where each entry came from. Also, I'm sorting the combined data set based on the timestamp, which I'm considering a simple Number for simplifying the example.

Once you have the data set combined, you can print them using another helper, which returns with or without **, depending on the origin:

output: function(obj) {
  var text = obj.value || "";
  if(obj.origin == 'history') text = "**"+text+"**";
  return text
}

Here's a sample code you can try:

HTML: hello

<body>
  {{> hello}}
</body>

<template name="hello">
  <ul>
    {{#each log}}
      <li>{{output this}}</li>
    {{/each}}
  </ul>
</template>

JS:

Commands = new Mongo.Collection("commands");
History  = new Mongo.Collection("history");

if (Meteor.isClient) {
  // counter starts at 0
  Session.setDefault('counter', 0);

  Template.hello.helpers({
    log: function () {
        var commands = Commands.find({}, { sort: { timestamp: 1 } }).map(function(i){i.origin='command'; return i;});
      var history  = History.find({}, { sort: { timestamp: 1} }).map(function(i){i.origin='history'; return i;});
      var combined = _.union(commands, history);
      return _.sortBy(combined, function(i) { return Number(i.timestamp) });
    },

    output: function(obj) {
      var text = obj.value || "";
      if(obj.origin == 'history') text = "**"+text+"**";
      return text
    }
  });

}

if (Meteor.isServer) {
  Meteor.startup(function () {
    Commands.remove({});
    History.remove({});
    for (var i=1; i<5; i++) {
      History.insert({value: 'history '+i, timestamp: 10*i});
      for (var j=1; j<4; j++) 
        Commands.insert({value: 'command '+i+'.'+j, timestamp: 10*i+j});
    }
  });
}