Reputation: 2710
Im new working with node, express and mongodb, so i don´t know if this is best way to implement this, i working in movie store ( Just for study and practicing ), where the is user is gonna have toolbar in the top with a search bar and is gonna be able to make a general search to find a movie/series/what ever else, now the way i was think i can implement this in express
with mongoose
was this way:
router.post('/search', (req, res) => {
let resultSearch = [];
Movie.find({ name: { $regex: req.body.query, $options: 'i' } })
.then(movies => {
if (movies.length > 0) {
const moviesSearch = movies.map(movie => {
return {
_id: movie._id,
content_type: movie.content_type,
rate: movie.rate,
name: movie.name,
item_img: movie.movie_img,
itemType: 'movies'
};
});
resultSearch = [...moviesSearch];
}
Serie.find({ name: { $regex: req.body.query, $options: 'i' } }).then(series => {
if (series.length > 0) {
const seriesSearch = series.map(serie => {
return {
_id: serie._id,
content_type: serie.content_type,
rate: serie.rate,
name: serie.name,
item_img: serie.serie_img,
itemType: 'series'
};
});
resultSearch = [...resultSearch, ...seriesSearch];
}
res.status(200).send(resultSearch);
});
})
.catch(error => {
console.log(error);
res.status(500).send(error);
});
});
so the idea here is to search between multiple collections, as you can see here what im doing is just search in one collection, in the response of the promise make the search in the other collection. Now i completely sure that is not a good way to do it, in the case that i want to search between 10 different collection is gonna be a really messy code, so is there a better way to achieve this.
Upvotes: 0
Views: 103
Reputation: 3122
You can use Promise.all
rather chaining promises when there's no dependency.
let moviesPromise = Movie.find({ name: { $regex: req.body.query, $options: 'i' } });
let seriesPromise = Serie.find({ name: { $regex: req.body.query, $options: 'i' } });
Promise.all([moviesPromise, seriesPromise]).then((res) => {
arr = ['movies', 'series'];
res.map((e, i)) => {
e.map(obj => {
return {
_id: obj._id,
content_type: obj.content_type,
rate: obj.rate,
name: obj.name,
item_img: obj.[`${arr[i]}_img`],
itemType: arr[i]
};
});
})
Upvotes: 3
Reputation: 11975
You can create an array contain Models you want to find in and names(because your img
field is based on the name) then loop through it and find with async/await
:
router.post('/search', async (req, res) => {
try {
let resultSearch = [];
let sets = [{model: Movie, name: 'movie'}, {model: Serie, name: 'serie'}, ...some more];
for (let set of sets) {
let results = await set.model.find({ name: { $regex: req.body.query, $options: 'i' } });
results = results.map(result => {
return {
_id: result._id,
content_type: result.content_type,
rate: result.rate,
name: result.name,
item_img: result[`${set.name}_img`],
itemType: set.name //or you can use set.model.collection.collectionName
};
})
resultSearch = resultSearch.concat(results);
}
res.status(200).send(resultSearch);
} catch(err) {
console.log(error);
res.status(500).send(error);
}
})
Update: As AZ_ suggest, using Promise.all
and then map the output to be expected response will give better performance:
router.post('/search', async (req, res) => {
try {
let sets = [{model: Movie, name: 'movie'}, {model: Serie, name: 'serie'}, ...some more];
let resultSearch = await Promise.all(sets.map(set => set.model.find({ name: { $regex: req.body.query, $options: 'i' } }).exec()));
resultSearch = resultSearch.map((results, i) => {
return results.map(result => {
return {
_id: result._id,
content_type: result.content_type,
rate: result.rate,
name: result.name,
item_img: result[`${sets[i].name}_img`],
itemType: sets[i].name //or you can use sets[i].model.collection.collectionName
};
})
}
res.status(200).send(resultSearch.flat()); //resultSearch is 2D array so need to flatten it
} catch(err) {
console.log(error);
res.status(500).send(error);
}
})
Upvotes: 2