I'm looking into adding full text search to a Meteor app. I know MongoDB now supports this feature, but I have a few questions about the implementation:
textSearchEnabled=true
) in a Meteor app?db.collection.ensureIndex()
) from within your app?db.quotes.runCommand( "text", { search: "TOMORROW" } )
) from within a Meteor app?Since my goal is to add search to Telescope, I'm searching for a "plug-and-play" implementation that requires minimal command line magic and could even work on Heroku or *.meteor.com.
The simplest way without editing any Meteor code is to use your own mongodb. Your mongodb.conf
should look something like this (on Arch Linux it is found at /etc/mongodb.conf
)
bind_ip = 127.0.0.1
quiet = true
dbpath = /var/lib/mongodb
logpath = /var/log/mongodb/mongod.log
logappend = true
setParameter = textSearchEnabled=true
The key line is setParameter = textSearchEnabled=true
, which, as it states, enables text search.
Start mongod
up
Tell meteor to use your mongod
not its own by specifying the MONGO_URL
environmental variable.
MONGO_URL="mongodb://localhost:27017/meteor" meteor
Now say you have collection called Dinosaurs
declared say in collections/dinosaurs.js
Dinosaurs = new Meteor.Collection('dinosaurs');
To create an text index for the collection create a file server/indexes.js
Meteor.startUp(function () {
search_index_name = 'whatever_you_want_to_call_it_less_than_128_characters'
// Remove old indexes as you can only have one text index and if you add
// more fields to your index then you will need to recreate it.
Dinosaurs._dropIndex(search_index_name);
Dinosaurs._ensureIndex({
species: 'text',
favouriteFood: 'text'
}, {
name: search_index_name
});
});
Then you can expose the search through a Meteor.method
, for example in the file server/lib/search_dinosaurs.js
.
// Actual text search function
_searchDinosaurs = function (searchText) {
var Future = Npm.require('fibers/future');
var future = new Future();
Meteor._RemoteCollectionDriver.mongo.db.executeDbCommand({
text: 'dinosaurs',
search: searchText,
project: {
id: 1 // Only take the ids
}
}
, function(error, results) {
if (results && results.documents[0].ok === 1) {
future.ret(results.documents[0].results);
}
else {
future.ret('');
}
});
return future.wait();
};
// Helper that extracts the ids from the search results
searchDinosaurs = function (searchText) {
if (searchText && searchText !== '') {
var searchResults = _searchEnquiries(searchText);
var ids = [];
for (var i = 0; i < searchResults.length; i++) {
ids.push(searchResults[i].obj._id);
}
return ids;
}
};
Then you can publish only documents that have been searched for in 'server/publications.js'
Meteor.publish('dinosaurs', function(searchText) {
var doc = {};
var dinosaurIds = searchDinosaurs(searchText);
if (dinosaurIds) {
doc._id = {
$in: dinosaurIds
};
}
return Dinosaurs.find(doc);
});
And the client side subscription would look something like this in client/main.js
Meteor.subscribe('dinosaurs', Session.get('searchQuery'));
Props to Timo Brinkmann whose musiccrawler project was the source of most this knowledge.
To create a text index and try to add like this I hope so it will be useful if there is still problem comment
From docs.mongodb.org:
Append scalar index fields to a text index, as in the following example which specifies an ascending index key on username:
db.collection.ensureIndex( { comments: "text", username: 1 } )
Warning You cannot include multi-key index field or geospatial index field.
Use the project option in the text to return only the fields in the index, as in the following:
db.quotes.runCommand( "text", { search: "tomorrow", project: { username: 1, _id: 0 } } )
Note: By default, the _id field is included in the result set. Since the example index did not include the _id field, you must explicitly exclude the field in the project document.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With