diff --git a/sample-app/redisearch-node-rest/NodeSearchService.js b/sample-app/redisearch-node-rest/NodeSearchService.js index 153388f..8496e4b 100644 --- a/sample-app/redisearch-node-rest/NodeSearchService.js +++ b/sample-app/redisearch-node-rest/NodeSearchService.js @@ -1,145 +1,140 @@ -const redis = require('redis'); -const redisearch = require('redis-redisearch'); +const redis = require('redis'); +const redisearch = require('redis-redisearch'); -let redisUrl = process.env.REDIS_URL || "redis://localhost:6379"; -let indexName = process.env.REDIS_INDEX || "idx:movie"; +const redisUrl = process.env.REDIS_URL || 'redis://localhost:6379'; +const indexName = process.env.REDIS_INDEX || 'idx:movie'; -console.log("Configuration Index: "+indexName+" - redisUrl: "+redisUrl); +console.log(`Configuration Index: ${indexName} - redisUrl: ${redisUrl}`); redisearch(redis); -let client = redis.createClient(redisUrl); +const client = redis.createClient(redisUrl); -let SearchService = function() { +const SearchService = function () { - let _search = function(queryString, options, callback) { + const _search = function (queryString, options, callback) { - let offset = 0; // default values - let limit = 10; // default value + let offset = 0; // default values + let limit = 10; // default value - - // prepare the "native" FT.SEARCK call - // FT.SEARCH IDX_NAME queryString [options] - let searchParams = [ - indexName, // name of thje inde - queryString, // query string, - "WITHSCORES" // return the score - ]; - // if limit add the parameters - if (options.offset || options.limit ) { - offset = options.offset||0; - limit = options.limit||10 - searchParams.push("LIMIT"); - searchParams.push(offset); - searchParams.push(limit); - } - // if sortby add the parameters - if (options.sortBy) { - searchParams.push("SORTBY"); - searchParams.push(options.sortBy); - searchParams.push( (options.ascending)?"ASC":"DESC" ); - + // prepare the "native" FT.SEARCH call + // FT.SEARCH IDX_NAME queryString [options] + const searchParams = [ + indexName, // name of the index + queryString, // query string + 'WITHSCORES' // return the score + ]; + + // if limit add the parameters + if (options.offset || options.limit) { + offset = options.offset || 0; + limit = options.limit || 10 + searchParams.push('LIMIT'); + searchParams.push(offset); + searchParams.push(limit); + } + // if sortby add the parameters + if (options.sortBy) { + searchParams.push('SORTBY'); + searchParams.push(options.sortBy); + searchParams.push((options.ascending) ? 'ASC' : 'DESC'); + } + + console.log(searchParams); + + client.ft_search( + searchParams, + function (err, searchResult) { + + const totalNumberOfDocs = searchResult[0]; + const result = { + meta: { + totalResults: totalNumberOfDocs, + offset, + limit, + queryString, + }, + docs: [], + raw_docs: searchResult } - console.log( searchParams ); - - client.ft_search( - searchParams, - function(err, searchResult) { - - let totalNumberOfDocs = searchResult[0]; - let result = { - "meta" : { - "totalResults" : totalNumberOfDocs, - "offset" : offset, - "limit" : limit, - "queryString" : queryString, - }, - "docs" : [], - "raw_docs" : searchResult - } - - // create JSON document from n/v paires - for (var i = 1; i <= searchResult.length-1 ; i++){ - let doc = { - meta : { - score : Number(searchResult[i+1]), - id : searchResult[i], - } - }; - i = i+2; - doc.fields = {}; - let fields = searchResult[i] - if (fields) { - for (var j=0, len=fields.length; j < len; j++) { - let idxKey = j; - let idxValue =idxKey+1; - j++; - doc.fields[fields[idxKey]] = fields[idxValue]; - } - } - result.docs.push(doc) - } - - - - callback(err,result); + // create JSON document from n/v pairs + for (let i = 1; i <= searchResult.length - 1; i++) { + const doc = { + meta: { + score: Number(searchResult[i + 1]), + id: searchResult[i] + } + }; + i = i + 2; + doc.fields = {}; + const fields = searchResult[i] + if (fields) { + for (let j = 0, len = fields.length; j < len; j++) { + const idxKey = j; + const idxValue = idxKey + 1; + j++; + doc.fields[fields[idxKey]] = fields[idxValue]; } - ); + } + result.docs.push(doc); + } - } + callback(err, result); + } + ); - let _getMovieGroupBy = function(field, callback) { - let retValue = { - totalResults : 0, - rows : [], - raw : [] // get the data as returned by the API - }; - - // prepare the "native" FT.AGGREGATE call - // FT.AGGREGATE IDX_NAME queryString [options] - let pipeline = [ - indexName, // name of thje inde - "*", // query string, - "GROUPBY", "1", `@${field}`, // group by - "REDUCE", "COUNT", "0", "AS", "nb_of_movies", //count the numbe rof movie by group - "SORTBY", "2", `@${field}`, "ASC", // sorted by the genre - "LIMIT", "0", "1000", // get all genre expecting less than 100 genres - ]; - - client.ft_aggregate( - pipeline, - function(err, aggrResult) { - - // transform array into document - // this should be added to a generic function - // ideally into the library itself - retValue.totalResults = aggrResult[0]; - - // loop on the results starting at element 1 - for (var i = 1; i <= aggrResult.length-1 ; i++){ - const item = aggrResult[i]; - let doc = {}; - for (var j=0, len=item.length; j < len; j++) { - doc[ item[j] ] = item[j+1] - doc[ item[j+2] ] = item[j+3] - j=j+3; - } - retValue.rows.push(doc); - } - retValue.raw = aggrResult; - callback(err,retValue); - }); + } - } + const _getMovieGroupBy = function (field, callback) { + const retValue = { + totalResults: 0, + rows: [], + raw: [] // get the data as returned by the API + }; + // prepare the "native" FT.AGGREGATE call + // FT.AGGREGATE IDX_NAME queryString [options] + const pipeline = [ + indexName, // name of the index + '*', // query string, + 'GROUPBY', '1', `@${field}`, // group by + 'REDUCE', 'COUNT', '0', 'AS', 'nb_of_movies', //count the number of movies by group + 'SORTBY', '2', `@${field}`, 'ASC', // sorted by the genre + 'LIMIT', '0', '1000' // get all genre expecting less than 100 genres + ]; + + client.ft_aggregate( + pipeline, + function (err, aggrResult) { + + // transform array into document + // this should be added to a generic function + // ideally into the library itself + retValue.totalResults = aggrResult[0]; + + // loop on the results starting at element 1 + for (let i = 1; i <= aggrResult.length - 1; i++) { + const item = aggrResult[i]; + const doc = {}; + for (let j = 0, len = item.length; j < len; j++) { + doc[item[j]] = item[j + 1]; + doc[item[j + 2]] = item[j + 3]; + j = j + 3; + } + retValue.rows.push(doc); + } + retValue.raw = aggrResult; + callback(err, retValue); + }); - return { - search: _search, - getMovieGroupBy: _getMovieGroupBy, - }; + } + return { + search: _search, + getMovieGroupBy: _getMovieGroupBy + }; } module.exports = SearchService; diff --git a/sample-app/redisearch-node-rest/README.md b/sample-app/redisearch-node-rest/README.md index 29e2a81..86bd72e 100644 --- a/sample-app/redisearch-node-rest/README.md +++ b/sample-app/redisearch-node-rest/README.md @@ -50,7 +50,7 @@ app.listen(port, () => { ``` -This will be the base of the various API endpoint +This will be the base of the various API endpoints. #### 4- Create a NodeSearchService @@ -70,7 +70,7 @@ You can run build and run the application from docker using the following comman ``` -This command will create a new image and build the maven project into it. +This command will create a new image and build the Node.js project into it. **Run** @@ -82,7 +82,20 @@ This command will create a new image and build the maven project into it. -p 8086:8086 redis/search-backend-node ``` +### Running the application locally + +To run the application on your local machine: + +```shell script +> npm install +> npm start +``` + +### Accessing the API + You can now access the REST Search service using the following URL: -* http://localhost:8086/api/1.0/search?q=man&limit=10&offset=20 +* http://localhost:8086/api/1.0/movies/search?q=man&limit=10&offset=20 + + diff --git a/sample-app/redisearch-node-rest/package.json b/sample-app/redisearch-node-rest/package.json index 94e557b..76f95ff 100644 --- a/sample-app/redisearch-node-rest/package.json +++ b/sample-app/redisearch-node-rest/package.json @@ -4,8 +4,12 @@ "description": "Sample RediSearch REST Server with Node.js", "main": "server.js", "scripts": { + "start": "node server.js", "test": "echo \"Error: no test specified\" && exit 1" }, + "engines": { + "node": ">=8.9.4" + }, "repository": { "type": "git", "url": "git+https://github.com/Redis-Developer/getting-started-redisearch.git" diff --git a/sample-app/redisearch-node-rest/server.js b/sample-app/redisearch-node-rest/server.js index b1485cd..98df293 100644 --- a/sample-app/redisearch-node-rest/server.js +++ b/sample-app/redisearch-node-rest/server.js @@ -1,60 +1,61 @@ -const express = require('express') -const cors = require('cors') -const app = express() +const express = require('express'); +const cors = require('cors'); +const app = express(); const serverPort = process.env.SERVER_PORT || 8086; const SearchService = require('./NodeSearchService'); -const searchService = new SearchService() +const searchService = new SearchService(); -app.use(cors()) +app.use(cors()); app.get('/api/1.0/movies/search', (req, res) => { - let queryString = req.query["q"]; - let offset = Number((req.query["offset"])?req.query["offset"]:"0"); - let limit = Number((req.query["limit"])?req.query["limit"]:"10"); - let sortBy = req.query["sortby"]; - let ascending = req.query["ascending"]; - - let options = { - offset : offset, - limit : limit - } + const queryString = req.query.q; + const offset = Number((req.query.offset)?req.query.offset:'0'); + const limit = Number((req.query.limit)?req.query.limit:'10'); + const sortBy = req.query.sortby; + const ascending = req.query.ascending; + + const options = { + offset, + limit + }; if (sortBy) { options.sortBy = sortBy; - options.ascending = true; // if sorted by default it is asceending + options.ascending = true; // if sorted by default it is ascending } if (ascending) { - options.ascending = (ascending==1 || ascending.toLocaleLowerCase()==="true"); + options.ascending = (ascending==1 || ascending.toLocaleLowerCase()==='true'); } searchService.search( - queryString, // query string - options, // options - function(err, result){ // callbacl - res.json(result); - }); + queryString, // query string + options, // options + function(err, result){ // callback + res.json(result); + } + ); }) app.get('/api/1.0/movies/group_by/:field', (req, res) =>{ - searchService.getMovieGroupBy(req.params['field'], function(err, result){ + searchService.getMovieGroupBy(req.params.field, function(err, result){ res.json(result); }); -}) +}); app.get('/api/1.0/', (req, res) => { - res.json({"status" : "started"}); -}) + res.json({status: 'started'}); +}); app.get('/', (req, res) => { - res.send('RediSearch Node REST Server Started') -}) + res.send('RediSearch Node REST Server Started'); +}); app.listen(serverPort, () => { - console.log(`RediSearch Node listening at http://localhost:${serverPort}`) -}) + console.log(`RediSearch Node listening at http://localhost:${serverPort}`); +});