Get Mongo's index as an array?

I’m working on a page with unique tags used in an image database. Now I wonder if it’s possible to create an index on Mongo db.collection.createIndex() and display the content of the index as an array. I’m assuming that a Mongo index has unique values similar to an index typically found at the end of a book.

Getting a simple array would be nice. Even better would be an array also including the occurrence for of each tag.

ps: At the moment I’m querying a collection on the server and sending the processed list of unique tags as an array via a method. It works fine, but I suspect this is a burden on the server since every time it has to go through all documents (currently 3834) to get a list of unique tags (currently 1691).

you can send “distinct” query on database using raw command.

1 Like

Here’s a quick code example for shock’s reply:

SomeCollection.rawCollection().distinct("somefield", function(res){
    
});`
1 Like

I’m getting an error …
(running Meteor 1.2.1)

Exception while invoking method 'getDistinctTags' TypeError: Object [object Object] has no method 'rawCollection'

The method

Meteor.methods({
	getDistinctTags() {
		const rawC = MyPix.rawCollection();
		const rawDistinct = Meteor.wrapAsync(rawC.distinct, rawC);
		return rawDistinct('metadata.tags');
	},
});

distinct works fine in the Mongo shell though:

> db.cfs.MyPix.filerecord.distinct("metadata.tags").sort()

[
	"apple",
	"banana",
	"grapefruit",
	"orange"
]

Here’s a full snippet of code I use:

Meteor.methods({
    getDistinctKeywords: function(){
        return Meteor.wrapAsync(function(callback){
            SomeCollection.rawCollection().distinct("keywords", callback);
        })();
    },
});

Simply calling this method will return all distinct values of the field “keyword” in the collection SomeCollection as defined in

SomeCollection = new Mongo.Collection("someCollection");

Try it out and let me know if it works or not, it seems MyPix in your example might not be a Mongo.Collection?

Thanks @nlammertyn — just tested your code on a regular collection and it worked.

Unfortunately rawCollection().distinct is still not working on the image collection set up with the Meteor-CollectionFS package. So you’re right, this seems to be the problem.

Any idea what to do? I seem to be unable to find any info how to use rawCollection with CollectionFS.

Aha, you didn’t mention collectionfs. To access the actual meteor collection behind a collectionfs collection (which aren’t the same) you’ll need to access .files. Let me quickly guide you through it.

So if you had setup collectionfs like so:

Files = new FS.Collection("files", {
    stores: [fileStore]
});

The way you’d access and run distinct on the actual collection would be: (note the.files)

 Files.files.rawCollection().distinct("field", callback);

Give that a try :wink:

1 Like

This worked!! Big thanks @nlammertyn!

For the record here’s the code I ended up with:
Method on server:

Meteor.methods({
  getDistinctTags() {
    // get unique tags only, via Mongo's distinct
    return Meteor.wrapAsync(function(callback) {
      MyPix.files.rawCollection().distinct('metadata.tags', callback);
    })();
  },
});

Client: Template, Helpers, etc:

Template.tags2.onCreated(function() {
  this.distinctTags = new ReactiveVar();
  Meteor.call('getDistinctTags', (error, result) => {
    if (error) {
      // do something
    } else {
      this.distinctTags.set(result); // save result reactive var
    }
  });
});

Template.tags2.helpers({
  tags: function() {
    const theTags = Template.instance().distinctTags.get();
    // turn theTags array to tags — and path-to-tags
    return _.map(theTags, aTag => {
      const params = {slug: aTag, page: '1'};
      const queryParams = {q: 'tag'};
      const pathToTag = FlowRouter.path('pool', params, queryParams);
      return {
        aTag,
        pathToTag,
      };
    });
  },
  tagsQuantity() {
    const tagsArray = Template.instance().distinctTags.get();
    return tagsArray.length;
  },
});

<template name="tags2">
  <div id="tagContainer">
    <ol>
    <strong>{{tagsQuantity}} tags2:</strong>
      {{ #each tags }}
        <span class="tag"><a href="{{ pathToTag }}">{{ aTag }}</a></span>
      {{ /each }}
    </ol>
  </div>
</template>

Thanks again!