Meteor collections

Hi All,

I am new to Meteor, so please excuse me if this is a basic question.

I have a Meteor app, and I am also using Ionic2 following this tutorial (I have the actual files instead of symlinks because that’s the only way I can get it to work on a remote server).

But I am getting the following error at runtime when I start the Ionic client:

Error: There is already a collection named "chats"

Which I believe comes from server/collections.ts, because when I remove the export I don’t get an error at startup, but when I try access the page that uses the collection, I get following error:

EXCEPTION: Error: Uncaught (in promise): EXCEPTION: Error in ./ChatsPage class ChatsPage_Host - inline template:0:0
ORIGINAL EXCEPTION: TypeError: collections_1.Chats is undefined
ORIGINAL STACKTRACE:
ChatsPage</ChatsPage.prototype.findChats@http://localhost:8100/build/js/app.bundle.js:104352:14

server/collections.ts

import {Mongo} from 'meteor/mongo';
import {Chat, Message} from 'api/models';
 
export const Chats = new Mongo.Collection<Chat>('chats');
export const Messages = new Mongo.Collection<Message>('messages');

Can anyone please advise?

UPDATE

I have found this, and added the following to my tsconfig.json.

“compileOnSave”: false, “buildOnSave”: false

but I still get the same error.

I believe I need to delete the compiled code ( .js and js.map files). Does anyone know where these are? Or is it possible to do some sort of clean?

What does the following do? Should I try this?

meteor reset

Thank you

meteor reset will “Reset the current project to a fresh state.” and removes the local mongo database. [manual]. I only need the command to remove the database sometimes, but I’d try it for any compiled/built issues as well.

Thanks. I tried meteor reset, but I still get the error.

Then I’d assume that meteor reset does not clear out built files, or at least not your built files (probably because it might not know about them). On the GitHub issue you found, drypa commented “this fix is correct. but also need delete compiled js files”. I’d expect them to be in a folder you did not personally create manually, and hopefully are named something like “built” or “output”, but might just be created directly into the Meteor /client/ and /server/ directories. Can you find files which you didn’t write (and which have the .js extension instead of .ts)?

Thanks stvrbbns.

There are many .js files, but non called collections.js or collections.js.map. Would it compile into a different name perhaps? Also, all of them are in the node_modules dir.

Do you think I should rather not use export const, and rather just get them each time I need the collection?

I do not know what name it would compile into (although I really would have expected it to compile into /server/collections.js), but you should be able to delete all the .js files since you wrote none of them. Let the system recompile all of the Typescript.

I think my error may be something else, and not due to the IDE compiling and creating duplicates.

If I delete my collections.ts file, and everywhere in the code where I was making use of the collection, I rather:

let Chats = new Mongo.Collection<Chat>('chats');

I get the error again:

Error: There is already a collection named "chats"

This means the error is not the collections.ts being complied twice, because it does not exist.

The problem seems to rather be related to how the collection is retrieved from the database I think. I don’t understand how Meteor controls database objects, but do you think this is correct? Or I am possibly retrieving it incorrectly by making a new collection each time?

@richardmarais : the usual reason for that error (disclosure: I haven’t done any angular coding) is that the SomeCollection = new Mongo.Collection('xyz') has been declared more than once in the same context (client or server). So I would look for places where you may have inadvertently done this: your file names do not seem to quite match with those in the tutorial, so maybe double check those as well.

2 Likes

Error: There is already a collection named "chats"

is because

new Mongo.Collection(‘chats’)

runs multiple times.

and @robfallows beat me to it. :slight_smile:

2 Likes

In the tutorial (Step 3), it uses symlinks instead of the actual files. When I have it set up with the symlinks, I don’t get this error. However, in order for it to work on a remote server, I had to replace the symlinks with the real files.

The symlinks were used in the meteor project, and pointed to the files in the Ionic project, so as to avoid duplication.

$ ln -s ../typings
$ ln -s ../tsconfig.json
$ ln -s ../tslint.json

Then you might really need the symlinks. Do you know if you are actively running a Meteor app, an Ionic app, or both?

Can you narrow down where the duplicate collection error is originating from?

I am running both inonic serve and meteor.

Maybe that’s the problem? My dir structure:

/theWhoZoo (ionic app)
/theWhoZoo/api (meteor app)

I run:

/theWhoZoo/ionic serve
/theWhoZoo/api/meteor

Should I perhaps move /api out of the /theWhoZoo dir?

(The reason I did this is because the tutorial did this)

The error is from the collections.ts file I think. But not 100% sure. Will continue to look.

I don’t know, but I’d guess that the duplicate collection error is originating in Meteor. That means it’s originating in /api/, so moving /api/ won’t fix the error. Also, symlinks should be read just as a normal file, so having a normal file [identical in content to the original] instead of a symlink should not make a difference.

Going back to your debugging attempt using let Chats = new Mongo.Collection<Chat>('chats'); instead of the collections.ts file, what happens if you only add the let Chats line to one file at a time. Can you narrow down which file or at least which context (client or server) is causing the error?

It’s working!

In methods.ts, if I remove any reference to collections.ts and rather do:

let Chats = new Mongo.Collection<Chat>('chats');

as you suggest, instead of referencing the constant. It works.

That means you were correct, and I can keep my dir structure. thank you

I think I need to get the collections.ts defining constants working. I need to make use of Chats in multiple places in the app. If I remove the constant, and just use let Chats = new Mongo.Collection<Chat>('chats'); in one place it works, but as soon as I need it in more than one place I get the error:

Error: There is already a collection named "chats"

I have a Java background, and there there is a concept of a Singleton, which would be suitable here I think. I will investigate if that is possible here.

I suggest that you think about the difference between let and var, consider what const actually does (“The const declaration creates a read-only reference to a value. It does not mean the value it holds is immutable, just that the variable identifier cannot be reassigned.”), and think about global and window.

The point of declaring let Chats = new Mongo.Collection<Chat>('chats'); in collections.ts is so that the collection will be available everywhere in the context of your code (as you identified - once and only once, thus singleton). Perhaps assign Chats explicitly to global (i.e. global.Chats = new…) within a check to make sure that Chats hasn’t been declared/assigned yet.

1 Like

How would you make Chats global?

collections.ts is as follows:

import {Mongo} from 'meteor/mongo';
import {Chat, Message} from 'api/models';

export const Chats = new Mongo.Collection<Chat>('chats');
export const Messages = new Mongo.Collection<Message>('messages');

The following gives a typscript error:

export const global.Chats = new Mongo.Collection<Chat>('chats');
export const global.Messages = new Mongo.Collection<Message>('messages');

error

[ts] ',' expected.
const global: any

Do you mean something similar to (this has Meteor errors):

import {Mongo} from 'meteor/mongo';
import {Chat, Message} from 'api/models';

var _Chats = new Mongo.Collection<Chat>('chats');
var _Messages = new Mongo.Collection<Message>('messages');


export const Chats = function Chats() {
    return _Chats;
}

export const Messages = function Messages() {
    return _Messages;
}

Sorry, I don’t know Typescript. In Javascript, it would be:

global.Chats = [the Chats collection]

somewhere that global is available and before a Chats reference is ever needed. Since you are using export, that implies to me that something else must be importing collections.ts. Looking at the tutorial, indeed it is:

  • line 3 of api/server/main.ts
  • line 4 of api/server/methods.ts
  • line 6 of app/pages/chats/chats.ts

So what if in main.ts you assign your imported Chats globally:

global.Chats = Chats;

or what if you remove the Chats import from main.ts since you aren’t actually using it there?

Another thought, if you keep collections.ts as it is supposed to be and have a bunch of import statements referencing it, then can you find which files already have Chats defined using console.log() before everything else in the file?

I really appreciate the guidance you are giving me.

I think I will try your option 2 first. Try and locate what is already using Chats.

If I cannot get success there, then I will look at I will assign Chats globally.

1 Like