Mongo.Cursor#map(callback, [thisArg]) with ECMAScript 6 arrow functions

I am using Meteor/Mongo and looking at the documentation, I am still not sure how to use the Cursor#map with ECMAScript 6 arrow functions.

I have a cursor:

private messages: Mongo.Cursor<Message>;

of Messages:

  interface Message {
    _id?: string;
    chatId?: string;
    senderId?: string;
    ownership?: string;
    content?: string;
    createdAt?: Date;
    changeDate?: boolean;
    readByReceiver?: boolean;
  }

and I would like to return a list of messages that match a specific _id.

When I try:

let _id: string = newMessage._id;
const matchedMessageIds: string[] = this.messages.map(({_id}) => _id)
    .reduce((result, _id) => result.concat(_id), []);

which kind of works, but it returns the results for the whole cursor, and not just the one matching the _id.

If you want an array of only those _ids which match your test _id, you should use the filter method on the resulting array of documents.

const filter_id: string = newMessage._id;
const matchedMessageIds: string[] = this.messages.map(({_id}) => _id)
  .filter(_id: string => _id === filter_id);

(Only just started learning ts, so please forgive any errors! :slight_smile:)

1 Like

Great thanks Rob.

TS is really cool, it makes Javascript more structured and easier to understand.

1 Like

Rob, do you know why this is happening? Is there a way I can handle it?

What does this.addMessage(message) do on your client?

It adds a row to local storage (SQLite).

My issue is that it is being called multiple times when Messages.insert on the server is called.

I don’t really understand it, but is there a way of making the observe stop?

I tried this, with no success:

if (message.lastMessageComp) {
  message.lastMessageComp.stop();
}

for

  interface Message {
    _id?: string;
    chatId?: string;
    senderId?: string;
    ownership?: string;
    content?: string;
    createdAt?: Date;
    changeDate?: boolean;
    readByReceiver?: boolean;
    lastMessageComp?: Tracker.Computation;
  }
  1. You can stop an observer. The observe method return a handle with a stop method:
const handle = cursor.observe(...);
// more code ...
handle.stop(); // to stop the observer.
  1. You would normally define an observer once for any cursor. Its presence in a function body bothers me, although I can’t see that it should cause an issue.

  2. Your workaround indicates you are running this inside an autorun (see point 2). It is true that stopping the computation will also stop an observer (if the observer is in the autorun).

  3. Are you observing this cursor (or another on the same collection) elsewhere?

  4. Other than stating that, all things being equal, your added should only be triggered once per new document, I don’t think I’m seeing enough code to comment sensibly. However, that’s never stopped me before :wink:

1 Like

Hmm:

  1. Since you appear to be running this in an autorun, you could try the reactive: false option on your cursor. From the observe docs:

If the cursor was created with the option reactive set to false, it will only deliver the initial results and will not call any further callbacks; it is not necessary to call stop on the handle.

1 Like

Thanks Rob, I am going through your options,

I thought the issue may be (2), because I do this multiple times:

  this.messages.observe({
    added: (message) => this.addMessage(message)
  });

So I put it in the constructor so it’s only done once. But it stops the page from loading, probably because this.messages has not been initialized yet.

Thank you for all the suggestions, I was feeling a little lost, but now I have a lot of things to try.

1 Like

I see this person has the same issue:

Thanks Rob, that solved my issue.

Need to make sure that the following is only done once. i.e singleton.

  this.messages.observe({
    added: (message) => this.addMessage(message)
  });
1 Like

Awesome! Glad you got it working :slight_smile:

1 Like