Attempt to search for a specific string - javascript

I'm trying to find a specific row in the database based on the user's message, namely: catalystname.
Within the schema I have successfully indexed the given string as text:
const { Schema } = mongoose;
const scheduleMessageSchema = new Schema({
_id: { type: Schema.Types.Oid, auto: true },
catalystname: String,
catalystdesc: String,
catalystquest: String,
date: String,
});
scheduleMessageSchema.index({catalystname: 'text'});
module.exports = mongoose.model('dbcatalyst', scheduleMessageSchema);
My search code:
const Catal = require("../src/models/dbcatalyst.js")
module.exports.run = async (client, message, args) => {
message.content = args.slice(0).join(" ")
Catal.find({$text: {$search: message.content}})
.exec(function(docs){
let embedlogs3 = new Discord.RichEmbed()
.setAuthor(`1`, message.author.displayAvatarURL)
.setDescription(`${docs}`)
.setColor("#33ffff")
message.channel.send(embedlogs3)
/*/ ${collected.first().content}/*/
});
}
And started searching for the required line in the message. The bot successfully copes with its task, but displays the entire document in full instead of 1 line.
_id: 5e243704961eb23c106bfb02,
catalystname: 'Чёрный Коготь',
catalystdesc: '0',
catalystquest: '0',
date: '1579430157018',
__v: 0
}
Can I somehow output exactly the string? catalystname

Looking at the Mongoose documentation, it seems the callback takes two parameters:
err An error or null
docs The returned document(s)
Change your callback to
Catal.find({$text: {$search: message.content}})
.exec(function(err, docs){
...
});
and you should receive an array of matching documents.

Related

Mongo findById() only works sometimes even when passed a valid ID

I am having a strange issue querying a Mongo DB collection. I am using findById() to get a single item that works sometimes and not others.
I have checked the id being passed to the server route and in all cases, they match perfectly with the targeted document in the collection.
Here is the basic code:
router.get("/:postId", async (req, res) => {
console.log('id : ', req.params.postId)
console.log('type: ', typeof(req.params.postId)) // id is a string
try {
const post = await Post.findById(req.params.postId).exec();
console.log('post :', post) // sometimes null
res.json(post);
} catch (err) {
res.json({ message: err });
}
});
In the above route, only certain posts will be found while others come back null. This happens regardless of whether the id passed is correct and the document exists with the exact id.
If anyone has any ideas about what could be going wrong here I'd much appreciate the help!
EDIT
I have done some more debugging and think it is something to do with the Schema for the Post model.
For example, this object will be found:
{
"tags": ["foo"],
"_id": "8394839483fhg020834903",
"title": "bar",
"content": "baz",
"isPrivate": true,
}
But this one will not because of the missing isPrivate property.
{
"tags": [],
"_id": "5e0fdc631ef5c46b285a4734",
"title": "New post",
"content": "Some content here",
}
I have tested this across multiple queries and it appears to the root of the problem.
I have tried adding
isPrivate: {
required: false
}
To the Schema but it doesn't seem to solve the issue.
Here is the full Schema
const postSchema = mongoose.Schema({
title: {
type: String,
required: true
},
content: {
type: String,
required: true
},
tags: [{ type: String }],
date: {
type: Date,
default: Date.now
},
isPrivate: {
type: Boolean
required: false
}
});
I'm not a Mongo/Mongoose expert, so any guidance would be much appreciated.
If post id match with any record it return data, otherwise it will return null. You should handle the exception
router.get("/:postId", async (req, res) => {
try {
const post = await Post.findById(req.params.postId).exec();
if(post) {
return res.json(post);
}
res.json({ message:'No Post found' });
} catch (err) {
res.json({ message: err });
}
});
You can manually check is record exists against a post id. You can use MongoDB Compass for gui browse the record
I believe the issue might be with your _id as per mongo standard _id should be a String is of 12 bytes or a string of 24 hex characters.
We can check if the _id is valid using mongoose.isValidObjectId()
I did run this check on your objects that you posted and indeed 1 is invalid while other is valid
const mongoose = require('mongoose');
console.log(`is '8394839483fhg020834903' valid - ${mongoose.isValidObjectId('8394839483fhg020834903')}`);
console.log(`is '5e0fdc631ef5c46b285a4734' valid - ${mongoose.isValidObjectId('5e0fdc631ef5c46b285a4734')}`);
It gives me
You will have to check what is modifying your ID's in the code, you can upload your schema to get a better understanding as well.

Mongoose array in document does not exist when queried

I need to query for all documents with an array but the returned documents dont have the array.
query
(async () => {
const data = await Lesson.find({signed: {$exists: true}});
console.log(data[0].signed); # undefined
})();
model
const lessonSchema = new mon.Schema(
{
day: Number,
startTime: Number,
endTime: Number,
description: {type: String, trim: true},
signed: [mon.Schema.Types.ObjectId]
},
{
collection: 'lessons'
}
);
module.exports = mon.model("Lesson", lessonSchema);
I checked the database and the documents do have the array.
The query retrieve everything except for the array (all of the documents and their values except for the array).
NOTE: in the database I have only two test documents. both have an array and both don't have the array in the query.
Thanks
EDIT: I found out that if I remove the signed property from the schema it works. Why?
I had this problem because the type of signed was objectId and the ids I used were strings. I cleared the array and added real ObjectId and it worked.

GraphQL resolver logic - Call query/mutation from mutation?

I am creating a workout/exercise logger, where user's can add a log of their set of an exercise to their account. User's will also be able to see their history of workouts and exercises (with set data). I am using mongoDB to store this data, with GraphQL and mongoose to query and mutate the data. I have seperated workout and exercise into their own types, as a workout object will only hold exercises and the sets that were recorded in the last 4 hours (duration of workout), while the exercise object will hold all sets that were ever logged by the user.
Type Definitions
type Workout {
id: ID!
workoutName: String!
username: String!
createdAt: String
exercises: [Exercise]!
notes: String
}
type Exercise {
id: ID!
exerciseName: String!
username: String!
sets: [Set]!
}
type Set {
id: ID!
reps: Int!
weight: Float!
createdAt: String!
notes: String
}
My problem lies in my resolver code for adding a set (mutation). This resolver should:
Query the database whether the exercise has ever been done by the user, by checking the name of the exercise with a match in the database, if there is a match, add the set data the user inputted to it, otherwise, create a new exercise entry first and then add the set to it.
Query the database whether there is a workout that has been done in the last 4 hours. If there isn't a match, create a new workout entry in the database. If there is a workout, check for a matching exercise name on the workout object to add the set data to or create a new exercise entry for it.
I realise that this mutation will be fairly large and will combine both the querying and mutation of data together. So I'm wondering if I can call seperate queries/mutations from my addSet resolver similar to a function call? Or is there another method that I should be going about this?
addSet Resolver
async addSet(_, { exerciseName, reps, weight, notes }, context) {
const user = checkAuth(context); // Authenticates and gets logged in user's details
if (exerciseName.trim() === '') {
throw new UserInputError('Empty Field', {
// Attached payload of errors - can be used on client side
errors: {
body: 'Choose an exercise'
}
})
} else {
exerciseName = exerciseName.toLowerCase();
console.log(exerciseName);
}
if ((isNaN(reps) || reps === null) || (isNaN(weight) || reps === null)) {
throw new UserInputError('Empty Fields', {
// Attached payload of errors - can be used on client side
errors: {
reps: 'Enter the number of reps you did for this set',
weight: 'Enter the amount of weight you did for this set'
}
})
}
// TODO: Check to see if the exercise has been done before by the user. If it has, then update the entry by adding the set data to it. If not create a new entry for the
// exercise and then add the data to it - Completed and working.
const exerciseExists = await Exercise.findOne({ exerciseName: exerciseName, username: user.username });
if (exerciseExists) {
console.log("This exercise exists");
exerciseExists.sets.unshift({
reps,
weight,
username: user.username,
createdAt: Date.now(),
notes
})
await exerciseExists.save();
//return exerciseExists;
} else {
console.log("I don't exist");
const newExercise = new Exercise({
exerciseName,
user: user.id,
username: user.username,
});
const exercise = await newExercise.save();
console.log("new exercise entry");
exercise.sets.unshift({
reps,
weight,
username: user.username,
createdAt: Date.now(),
notes
})
await exercise.save();
//return exercise;
}
// TODO: Get the most recent workout from the user and check if the time it was done was from the last 4 hours. If it wasn't, create a new workout entry for the user.
// If it was within the ast 4 hours, check to see if the workout has an exercise that matches with one the user inputted. If there isn't an exercise, create a new entry
// and add the set data to it, otherwise update the existing entry for the exercise.
const workoutExists = await Workout.findOne({ username: username }).sort({ createdAt: -1 }); // Gets most recent workout by user
const now = Date.now();
if (now > workoutExists.createdAt + 14400000) { // Checks to see if the workout was less than 4 hours ago
console.log("workout was from another session");
// rest of code not implemented yet
} else {
console.log("workout is still in progress");
// rest of code not implemented yet
}
},

Mongoose : Cast to ObjectId failed for value "Some String" at path "_id"

New to MongoDB, Javascript stack and need help understanding cause of this error.
I have my model created :
const
Mongoose = require('mongoose');
Schema = Mongoose.Schema,
Model = Mongoose.model;
module.exports = Model('Project',
new Schema({
icon : String,
name : String,
state : String,
number : String
})
);
This is my MongoDB document :
[![MongoDB Document][1]][1]
I am attempting to receive all the documents in the collection when I call the API so therefore as per the Mongoose document I am using the find() method.
Here is my API Implementation:
const Project = require('../../models/project');
router.get('/projects/:page?/:limit?',
function(req, res, next){
const page = Math.max(req.params.page || 1, 1) - 1;
const limit = Math.max(req.params.limit || 20, 20);
//Verified : I am hitting the API
console.log("Reached API /projects");
Project.find()
.populate('icon')
.populate('name')
.populate('state')
.populate('number')
.limit(limit).skip(page * limit).exec(
function(err, project)
{
if (err) { return next(err); }
res.send(project);
}
); //End of exec()
}//End of unction
);
I am successful in making the API call using fetch() but I am receiving "Cast to ObjectId failed error" for all the String values.
I believe there is something really simple within my Mongo DB document that I might be missing. Please help me understand and solve this issue.
**EDIT ---
The error seems to point at the string values of the keys:
**
Thank you
Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s). So you're Id cast is not valid, because of string, you need to have ObjectId, some changes need to be made before it, Let's debug:
const alldata = await Project.find()
console.log(alldata) // ?
does this return something, I'm using async await here if it return data then the problem is with your populate because your Id case isn't valid as you save in schema string and you're referring here populate, example of using populate:
module.exports = Model('Project',
new Schema({
icon : [{ type: Schema.ObjectId, ref: 'your icon document' }],
name : [{ type: Schema.ObjectId, ref: 'you name document' }],
state : [{ type: Schema.ObjectId, ref: 'state document' }],
number : [{ type: Schema.ObjectId, ref: 'number document' }]
})
);
but it seems to me that you don't need to use the populate because you have simple data, name, number... so you should be good to go with the above example
Resources: mongoose fetching data, using populate, relation

Adding to an array in MongoDB using $addToSet

I'm trying to add data to an array defined in my mongoDB called "signedUp" it is within my Timetable Schema. So far i've been able to update other fields of my schema correctly however my signedUp array always remains empty. I ensured the variable being added was not empty.
Here is my Schema
var TimetableSchema = new mongoose.Schema({
date: {
type: String,
required: true,
trim: true
},
spaces: {
type: Number,
required: true
},
classes: [ClassSchema],
signedUp: [{
type: String
}]
});
This was my latest attempt but no value is ever added to the signedUp array.
My API update request
id = {_id: req.params.id};
space = {spaces: newRemainingCapacity};
signedUp = {$addToSet:{signedUp: currentUser}};
Timetable.update(id,space,signedUp,function(err, timetable){
if(err) throw err;
console.log("updates");
res.send({timetable});
});
Thanks
You can take a look at db.collection.update() documentation. Second parameter takes update and 3rd one represents operation options while you're trying to pass your $addToSet as third param. Your operation should look like below:
id = {_id: req.params.id};
space = { $set: { spaces: newRemainingCapacity }};
signedUp = { $addToSet:{ signedUp: currentUser}};
update = { ...space, ...signedUp }
Timetable.update(id,update,function(err, timetable){
if(err) throw err;
console.log("updates");
res.send({timetable});
});
space and signedUp are together the second argument.
try this:
id = {_id: req.params.id};
space = {spaces: newRemainingCapacity};
signedUp = {$addToSet:{signedUp: currentUser}};
Timetable.update(id, {...space, ...signedUp}, function(err, timetable){
if(err) throw err;
console.log("updates");
res.send({timetable});
});

Categories