How to display search result with mongoose pagination - javascript

I have Training Collection with lots of data. All function works except that on search result the latest entry results appear correctly, but the old results don't appear on front except they appear on the pages based on their position. Helper and course are populated from another schema. The reason I used the if condition is because the helper and course are populated. I tried searching for similar problem on stack overflow and other website and tried to query it as 'helper.first_name': { $regex: reg_ex } but it did not work for me that way. Here is the pseudo code below
P.s I am using pagination. I need help please
req.checkBody('search').notEmpty().withMessage('Please enter a query'); // check empty entry
const reg_ex = new RegExp(req.body.search, 'i'); // regular expression
const page = parseInt(req.query.page);
const limit = 20;
const skipIndex = (page - 1) * limit;
try {
Training
.find()
.populate([{
path: 'helper',
model: Helper
},
{
path: 'course',
model: Course
},
{
path: 'user',
select: '-password'
}
])
.sort({
_id: -1
})
.limit(limit)
.skip(skipIndex)
.exec(function (err, doc) {
if (err) {
return next(err)
}
const arryPush = [];
doc.forEach(data => {
if (
(data.batch.match(reg_ex) != null) ||
(data.helper.first_name.match(reg_ex) != null) ||
(data.helper.last_name.match(reg_ex) != null) ||
(data.helper.phone.match(reg_ex) != null) ||
(data.helper.email.match(reg_ex) != null) ||
(data.course[0].title.en.match(reg_ex) != null)
) {
arryPush.push({
_id: data._id,
course: [{
title: {
en: data.course[0].title.en,
am: data.course[0].title.am
}
}],
is_rejected: data.is_rejected,
approved: data.approved,
training_completion_status: data.training_completion_status,
training_time: data.training_time,
weekdays: data.weekdays,
payment_option: data.payment_option,
batch: data.batch,
created_at: data.created_at,
helper: {
first_name: data.helper.first_name,
last_name: data.helper.last_name,
phone: data.helper.phone,
email: data.helper.email
}
})
}
});
res.status(200).json(arryPush)
});
} catch (e) {
res.status(500).json({
message: "Error Occured" + e
});
}

Related

How to use select on azure search suggesters

I'm using Azure search on my project, and I want to do an autocomplete text field, it works as expected. here's the code :
const suggestItems = async (req, res) => {
try {
// Reading inputs from HTTP Request
const q = (req.query.q || (req.body && req.body.q));
const top = (req.query.top || (req.body && req.body.top));
const suggester = (req.query.suggester || (req.body && req.body.suggester));
// Let's get the top 5 suggestions for that search term
const suggestions = await client.suggest(q, suggester, { top: parseInt(top) });
//const suggestions = await client.autocomplete(q, suggester, {top: parseInt(top)});
console.log(suggestions.results)
return res.status(status.OK)
.json({ suggestions: suggestions.results})
} catch (error) {
handleError(res, error)
}
}
her's the result :
[
{ text: 'Alpha Aromatics (MA)', document: { id: '4' } },
{ text: 'Alpha Aromatics (USA)', document: { id: '5' } },
{ text: 'Art Land - Winter Palace', document: { id: '6' } },
{ text: 'Alpha Aromatics (USA)', document: { id: '3' } }
]
here's the quesry passed by postman :
{
"q":"ar","top":5,"suggester":"sg"
}
but the problem is , on the result I have just the text and the id of the document , I'm looking for other fields like status for example, how can get that please ?
I am guessing "Status" is one of your index fields, from the question. You need to make sure you mark the fields you need to be returned in the results as retrievable in your index definition. It looks you only have text and id fields as retrievable. For more information: https://learn.microsoft.com/en-us/azure/search/search-what-is-an-index.
Example:

Mongoose - CastError Cast to string failed for value "Object"

I have Mongoose CastError issue. I made a nodeJs API. At the specific route, it returns data appended with some other data. I saw many fixes available here but my scenario is different.
Here is my model and the problem occurs at fields property.
const deviceSchema = new Schema({
device_id: { type: String, required: true },
user_id: { type: Schema.Types.ObjectId, ref: 'User', require: true },
location_latitude: { type: String, default: '0' },
location_longitude: { type: String, default: '0' },
fields: [{ type: String }],
field_id: { type: Schema.Types.ObjectId, ref: 'Field', required: true },
timestamp: {
type: Date,
default: Date.now,
},
});
and my controller is
exports.getAllDevices = async (req, res) => {
try {
let devices = await Device.find({})
.sort({
timestamp: 'desc',
})
.populate('user_id', ['name']);
// Let us get the last value of each field
for (let i = 0; i < devices.length; i++) {
for (let j = 0; j < devices[i].fields.length; j++) {
if (devices[i].fields[j] !== null && devices[i].fields[j] !== '') {
await influx
.query(
`select last(${devices[i].fields[j]}), ${devices[i].fields[j]} from mqtt_consumer where topic = '${devices[i].device_id}'`
)
.then((results) => {
************** Problem occurs here **************
if (results.length > 0) {
devices[i].fields[j] = {
name: devices[i].fields[j],
last: results[0].last,
};
} else {
devices[i].fields[j] = {
name: devices[i].fields[j],
last: 0,
};
}
************** Problem occurs here **************
});
}
}
}
// Return the results
res.status(200).json({
status: 'Success',
length: devices.length,
data: devices,
});
} catch (err) {
console.log(err);
res.status(500).json({
error: err,
});
}
};
It actually gets data from InfluxDB and appends it to fields property which was fetched from MongoDB as mentioned in my model. But it refused to append and CastError occurs.
After addition, it will look like this
I can't resolve this error after trying so many fixes. I don't know where I'm wrong. Please suggest to me some solution for this.
I can see you are not using devices variable as Mongoose Document. devices is an array of Documents.
I would like to suggest you to use lean() function to convert from Document to plain JavaScript object like
let devices = await Device.find({})
.sort({
timestamp: 'desc',
})
.populate('user_id', ['name'])
.lean();

How to access array elements that are defined in another array of Mongoose scheme object Array?

This is the User schema in mongoose:
var userSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true,
},
name: {
type: String,
required: true,
},
Addtasks: [
{
topic: String,
words: Number,
keywords: String,
website: String,
otherdetails: String,
exampleRadios: String,
deadline: Date,
Date: String,
fileName: String,
Bigpaths: [],
},
],
});
module.exports = mongoose.model('User', userSchema);
I want to use/access the Bigpaths array, which is defined inside the Addtasks array, which is defined in User. Data is already are there in mongoDB, which I have inserted via UI page. I am trying the following code but I am getting this error in console:
data.Addtasks[Object.keys(data.Addtasks).length - 2].Bigpaths.forEach(
(element) => {
// ...
}
)
as
TypeError: Cannot read property 'Bigpaths' of undefined
at \Desktop\grumpytext\routes\index.js:99:71
Code:
const { files } = req;
User.findOne({ email: req.user.email }, function (error, data) {
if (error) {
console.log('Three');
} else if (data) {
if (Object.keys(data.Addtasks).length > 1) {
data.Addtasks[Object.keys(data.Addtasks).length - 2].Bigpaths.forEach(
(element) => {
files.forEach((currentElement) => {
if (element.name == currentElement.filename) {
files.pull(currentElement.filename);
}
});
}
);
}
}
});
How to resolve this error or how to access all the elements of Bigpaths array so that I can iterate it with forEach loop?
I'm not sure here, but I think you need to populate Addtasks prior to manipulating it:
const files = req.files;
User.findOne({email:req.user.email}).populate('Addtasks').exec((error, data) => {
if (error) {
console.log("Three");
}
else
{
if(data)
{
if(Object.keys(data.Addtasks).length > 1)
{
console.log("Addtasks count: " + Object.keys(data.Addtasks).length);
data.Addtasks[Object.keys(data.Addtasks).length - 2].Bigpaths.forEach(element => {
files.forEach(currentElement => {
if(element.name == currentElement.filename)
{
files.pull(currentElement.filename);
}
})
});
}
}
}
});
Please notice the log console.log("Addtasks count: " + Object.keys(data.Addtasks).length); - in case the solution does not work, I advise to add some prints, especially to check if the count of elements is as expected or properties within an object are fine.

Retrieve n random document with certain filters MongoDB

I need to retrieve from a collection of random docs based on a limit given.
If some filters are provided they should be added to filter the results of the response. I'm able to build the match and size based on the fields provided but even tho I have 20 documents that meet the filter when I make the call I receive only 2 or 3 docs back and I can't seem to figure it out. If I set only the limit it does give me back N random docs based on the limit but if I add a filter it won't give me the wanted results.
This is what I do now
const limit = Number(req.query.limit || 1);
const difficulty = req.query.difficulty;
const category = req.query.category;
const settings = [
{
$sample: {
size: limit
}
}
];
if (difficulty && category) {
settings.push({
$match: {
difficulty: difficulty,
category: category
}
});
} else if (difficulty && category == null) {
settings.push({
$match: {
difficulty
}
});
}
if (difficulty == null && category) {
settings.push({
$match: {
category
}
});
}
console.log(settings);
Question.aggregate(settings)
.then(docs => {
const response = {
count: docs.length,
difficulty: difficulty ? difficulty : "random",
questions:
docs.length > 0
? docs.map(question => {
return {
_id: question._id,
question: question.question,
answers: question.answers,
difficulty: question.difficulty,
category: question.category,
request: {
type: "GET",
url:
req.protocol +
"://" +
req.get("host") +
"/questions/" +
question._id
}
};
})
: {
message: "No results found"
}
};
res.status(200).json(response);
})
.catch(err => {
res.status(500).json({
error: err
});
});
Order of the stages matters here. You are pushing the $match stage after the $sample stage which first put the $size to whole the documents and then applies the $match stage on the $sampled documents documents.
So finally you need to push the $sample stage after the $match stage. The order should be
const limit = Number(req.query.limit || 1);
const difficulty = req.query.difficulty;
const category = req.query.category;
const settings = []
if (difficulty && category) {
settings.push({
$match: {
difficulty: difficulty,
category: category
}
})
} else if (difficulty && category == null) {
settings.push({
$match: {
difficulty
}
})
}
if (difficulty == null && category) {
settings.push({
$match: {
category
}
})
}
setting.push({
$sample: {
size: limit
}
})
console.log(settings);
Question.aggregate(settings)

nodejs mongoose model / relations questions

I recently discovered nodejs + mongodb (via mongoosejs).
I am coding a small app for my raspberry to display a scoreboard on a big led pannel.
I actually have 2 problems
To configure the scoreboard for a match I need :
2 teams : each teams has n players ( 1 to .... )
A time limit
A goal limit
the goals scored by each team
Here is my models files :
var MatchSchema = new Schema({
teams: [{ type: Schema.Types.ObjectId, ref: 'Team' }],
goals_left: Number,
goals_right: Number,
time_limit: Number,
goal_limit: Number
});
var TeamSchema = new Schema({
name: {
type: String,
required: [true, "Team Name is required"],
},
players: [{ type: Schema.Types.ObjectId, ref: 'Player' }]
});
var PlayerSchema = new Schema({
name: {
type: String,
required: [true, "Player Name is required"],
}
});
Question 1 :
Create team : I have no problem to insert in my Teams collection an array of player object ( I use checkboxes to select the players of the team )
Create match : I can't manage to insert an array of 2 team objects in my match collection, here is the form and the controller action :
Form
div.row.form-group
each i in [0,1]
div.col
label(for='teams-'+i) #{ i===0 ? 'Left' : 'Right' } Team
select.form-control(type='select' id='teams-'+i placeholder='Select TEAM'+i name='teams['+i+']' required='false' data-target='/team/new')
option(value=null) Select #{ i===0 ? 'Left' : 'Right' } Team
for team in all_teams
option(value=team._id) #{team.name}
Create match code :
// Handle Match create on POST.
exports.match_create_post = [
(req, res, next) => {
if(!(req.body.teams instanceof Array)){
if(typeof req.body.teams==='undefined') {
req.body.teams=[];
}else{
match_teams=new Array(req.body.teams);
}
}
next();
},
(req, res, next) => {
const errors = validationResult(req);
// Create a team object with escaped and trimmed data.
var match = new Match(
{
//teams: [ "5a92f691d5038fd56c648664", "5a92fa14b4d7f5d665da9ef4"],
teams: match_teams,
time_limit: req.body.time_limit,
goal_limit: req.body.goal_limit,
status: req.body.status
}
);
if (!errors.isEmpty()) {
res.render('match_form', { title: 'Create Match', match: match, errors: errors.array()});
return;
} else {
match.save(function (err) {
if (err) { return next(err); }
res.redirect(match.url);
});
}
}
];
The weird thing is I do the same thing for creating a team and it works perfeclly...
I can not understand why req.body.teams is undefined
Question 2 :
If I manually insert the 2 teams in my teams fields like :
teams: [ "5a92f691d5038fd56c648664", "5a92fa14b4d7f5d665da9ef4"]
When I want to display match detail :
Controller Query :
exports.match_detail = function(req, res, next) {
var id = mongoose.Types.ObjectId(req.params.id);
async.parallel({
match: function(callback) {
Match.findById(id)
.populate('teams')
.populate('teams.players')
.exec(callback);
},
}, function(err, results) {
if (err) { return next(err); }
if (results.match==null) {
var err = new Error('Match not found');
err.status = 404;
return next(err);
}
// Successful, so render
res.render('match', {
title: 'match Detail',
match: results.match
} );
});
};
The team names are correctly displayed but for player details I only can access the _id, not the name
Any help would be appreciated :-)
Thank you
Clément

Categories

Resources