JQuery autocomplete search with Node.js and Mongoose

mars 13th, 2013

I was striving to find for the most robust solution, for an autocomplete search field implemented with JQuery UI, on client side, and NodeJS on the server side. And after implementation’s tests, I discovered that NodeJS and Mongoose will provide a efficient solution.

The client side, with JQuery, is the one configured out on their site with some adjustements on field names and on the return events after the query has succeed. The datasource is a server side script which return JSON data, from a GET resource build with Node.js, Express.js and Mongoose.

The client side

The client side script from the JQuery autocomplete example work has follow. The autocomplete client script send a GET query to the server with input field data. The success event return an array of JSON object which is map in a callback to apply to each value in that array. The goal of that call is to assemble an array of objects, with label and value attribute, for preparing the data to be used in all different events.

Here is the client script :


$(function () {

  $("#search-query").autocomplete({
      source: function (request, response) {
         $.ajax({
            url: "/search_member",
            type: "GET",
            data: request,  // request is the value of search input
            success: function (data) {
              // Map response values to fiedl label and value
               response($.map(data, function (el) {
                  return {
                     label: el.fullname,
                     value: el._id
                  };
                  }));
               }
            });
         },
         
         // The minimum number of characters a user must type before a search is performed.
         minLength: 3,
         
         // set an onFocus event to show the result on input field when result is focused
         focus: function (event, ui) {
            this.value = ui.item.label;
            // Prevent other event from not being execute
            event.preventDefault();
         },
         select: function (event, ui) {
            // Prevent value from being put in the input:
            this.value = ui.item.label;
            // Set the id to the next input hidden field
            $(this).next("input").val(ui.item.value);
            // Prevent other event from not being execute            
            event.preventDefault();
            // optionnal: submit the form after field has been filled up
            $('#quicksearch').submit();
         }
  });

});

The server side

On the server side, we have declared a new mongoose User which will be in charge to query the informations from searched terms. When the query is fired from the client side, node.js with express.js use a app.get() routing system to intercept the route /search_member.

The searched term is retrieve in the request like so : req.query[‘term’]. We use the mongoose’s query builder to construct query. With the find() method, you can select document in a collection with regex argument and use the projection to control fields to be return. The find() method always includes the _id field even if the field is not explicitly stated to return in the projection parameter. For the need of our application, we also sort with updated_at and created_at and limit it to 20 the returned results. And finally the json array result set is returned with res.send().

Here is the server script :


User = mongoose.model('User'); // Declare a new mongoose User

app.get('/search_member', function(req, res) {
   var regex = new RegExp(req.query["term"], 'i');
   var query = User.find({fullname: regex}, { 'fullname': 1 }).sort({"updated_at":-1}).sort({"created_at":-1}).limit(20);
       
      // Execute query in a callback and return users list
  query.exec(function(err, users) {
      if (!err) {
         // Method to construct the json result set
         var result = buildResultSet(users);
         res.send(result, {
            'Content-Type': 'application/json'
         }, 200);
      } else {
         res.send(JSON.stringify(err), {
            'Content-Type': 'application/json'
         }, 404);
      }
   });
});

It’s fairly straightforward and it just works !

  • Emir Mamashov

    thanks, it’s cool!