fetching data from mongodb and electron js using ipc renderer - mongodb

vue file
this.$electron.ipcRenderer.send('get-result')
this.$electron.ipcRenderer.on('got-it', (event, data) => {
if (data.status) {
this.allResult = data.result
}
else{
this.allResult = ''
}
})
renderer file
ipcMain.on('get-result', (event) => {
todolist.find({}, null, {sort: { creationDate: -1 }}, (err, result) => {
if (!err && result.length) {
event.sender.send('got-it', {
status: true,
result: result
});
} else {
event.sender.send('got-it', {
status: false
});
}
});
});
IN CMD results look like this which is OK
[ { _id: 5dd01fff35ad336558153f8c,
notes: 'hello 3',
creationDate: 2019-11-16T16:12:47.190Z,
__v: 0 },
{ _id: 5dd01efdca8cdf61daa07fcf,
notes: 'Hello Again',
creationDate: 2019-11-16T16:08:29.190Z,
__v: 0 },
{ _id: 5dd01d7a2a4b995f68d36f7c,
notes: 'Hello Mongo Atlas',
creationDate: 2019-11-16T16:02:02.998Z,
__v: 0 },
{ _id: 5dd01c72d43db25eb93c0267,
notes: 'hello mongo',
creationDate: 2019-11-16T15:57:38.799Z,
__v: 0 } ]
But after getting result from renderer browser console look like this
0:$__:(...)
$init:(...)
$locals:(...)
isNew:(...)
_doc:(...)
__ob__
:Observer {value: {…}, dep: Dep, vmCount: 0}
get $__:ƒ reactiveGetter()
set $__:ƒ reactiveSetter(newVal)
get $init:ƒ reactiveGetter()
set $init:ƒ reactiveSetter(newVal)
get $locals:ƒ reactiveGetter()
set $locals:ƒ reactiveSetter(newVal)
and final results are in under the _doc of every index like 0, 1, 2
why is that ? I think it supposed to return just simple array like CMD's printed result.
Is that anything left to fetching organize result or i need to do something else ?
Thank you

Best way ignore this type of format is, after getting result from DB encode in json and then of font-end decode json format which will generate desire result. Like this-
render.js
ipcMain.on('get-result', (event) => {
todolist.aggregate([
{
$sort:{
_id:-1
}
}
])
.exec((err, result) => {
if (!err && result.length) {
event.sender.send('got-it', {
status: true,
result: JSON.stringify(result)
});
} else {
event.sender.send('got-it', {
status: false
});
}
});
});
component.vue
this.$electron.ipcRenderer.send('get-result')
this.$electron.ipcRenderer.on('got-it', (event, data) => {
if (data.status) {
this.allResult = JSON.parse(data.result)
}
else{
this.allResult = ''
}
})

Related

Mongoose - Update/Find Specific Object in an Array Not Working As Expected

I am following the docs without luck and am at a standstill while trying to update an object in an object in an array using MongoDB and Mongoose.
Here is my document:
{
fields: [
{ id: 603d63086db2db00ab09f50f, data: [Object] },
{ id: 603d63086db2db00ab09f510, data: [Object] },
{ id: 603d63086db2db00ab09f511, data: [Object] },
{ id: 603d63086db2db00ab09f512, data: [Object] },
{ id: 603d63086db2db00ab09f513, data: [Object] },
{ id: 603d63086db2db00ab09f514, data: [Object] },
{ id: 603d63086db2db00ab09f515, data: [Object] }
],
layouts: [],
_id: 603d631a6db2db00ab09f517,
bandId: '603d63146db2db00ab09f516',
eventType: 'private',
ownerId: '6039354906410800c14934c1',
__v: 0
}
I am trying to updateOne of the fields.data in the fields array. fields.data is an object as well.
I call my Express/Node Backend to this route.
//Update
router.put("/:id", async (req, res) => {
try {
let updating = await QuoteGenerator.updateOne(
{ _id: req.params.id, "fields.id": req.body.id },
{
"$set": {
"fields.$.data": req.body.data,
},
}
);
let item = await QuoteGenerator.findOne({ _id: req.params.id });
res.json({ success: "Item Updated.", item });
} catch (err) {
console.log(err);
res.json({ error: "Something went wrong when updating this item." });
}
});
Where req.body is:
{ id: '603d63086db2db00ab09f50f', data: { type: 1, rate: '200.30' } }
**Just in case it's helpful, here is what one of the fields objects looks like in the document,
{"id":"603d63086db2db00ab09f50f","data":{"type":1,"rate":300}}
I have even tried changing my route to find this document - which I have confirmed exists - Truly at a loss why it won't find the document.
Here is how I changed the above route to find the document.
//Update
router.put("/:id", async (req, res) => {
try {
let updating = await QuoteGenerator.find(
{ _id: req.params.id, "fields.id": req.body.id },
);
console.log(updating) //returns []
let item = await QuoteGenerator.findOne({ _id: req.params.id });
res.json({ success: "Item Updated.", item });
} catch (err) {
console.log(err);
res.json({ error: "Something went wrong when updating this item." });
}
});
The Model
//Create Schema - QG
const QuoteGeneratorSchema = new Schema({
bandId: {
type: String,
required: true,
},
ownerId: {
type: String,
required: true,
},
fields: {
type: Array,
default: defaultFields,
required: true,
},
eventType: {
type: String,
required: false,
},
layouts: {
type: Array,
required: false,
},
});
let QuoteGenerator = mongoose.model("QuoteGenerator", QuoteGeneratorSchema);
module.exports = QuoteGenerator;
Any nudge in the right direction to replacing that data object with a new data object would be extremely helpful! Thanks!

I am learning express and mongoose and I cannot get a schema to save, but can see it with console.log()

EDIT: I think weekCount is saving before the records are loaded into it. Perhaps incorrect use of the find()?
I have started a website to record animals in camps (paddocks). I am using express, mongo, mongoose, and pug.
I have a schema (see below) that has an array of type: Schema.Types.ObjectId that I can not save to mongo. The array is empty.
I have a form that fetches the camp names, and the animal types (cows, bulls, calves) and creates a form.
The form is displayed, and the POST can read the form data. The form data is read into schema and is displayed ok with console.log, but does not save the entire schema in mongo.
I have read a lot of posts, and tried many things such as markModified, used a full Schema.
Its been hours now, and I would appreciate some help.
Express mongoose Models:
var WeekCountSchema = new Schema({
dateOfCount: { type: Date },
campCounts: [{type: Schema.Types.ObjectId, ref: 'CampCount'}] < ----- problem
});
var CampCountSchema = new Schema({
campName: String,
campCountDate: Date,
count: {
ox: Number,
cow: Number,
bull: Number,
heifer: Number,
calf: Number,
weaner: Number
}
});
weekCountController:
Scroll Down to the <----
exports.weekCount_create_post = [
validator
.body("dateOfCount", "Week Count Data Required")
.toDate()
.isLength({ min: 1 })
.trim(),
validator.sanitizeBody("*").escape(),
(req, res, next) => {
var weekCount = new WeekCount({
dateOfCount: req.body.dateOfCount
});
const errors = validator.validationResult(req);
if (!errors.isEmpty()) {
// There are errors. Render the form again with sanitized values/error messages.
console.log("ERRORS!s");
async.parallel(
{
camps: function(callback) {
Camp.find()
.sort("name")
.exec(callback);
},
cattleClasses: function(callback) {
CattleClass.find(callback);
}
},
function(err, results) {
if (err) {
return next(err);
}
res.render("weekCount_form", {
title: "There were Errors! New Week Count",
camps: results.camps,
cattleClasses: results.cattleClasses
});
}
);
return;
} else {
// Data from form is valid.
Camp.find({}, "name").exec(function(err, list_camps) {
if (err) {
return next(err);
}
CattleClass.find({}, "name").exec(function(err, list_cattleClasses) {
if (err) {
return next(err);
}
var campCountArray = [];
list_camps.forEach(function(campName) {
var campCount = new CampCount({
campName: campName.name
});
var emptyCount = true;
list_cattleClasses.forEach(function(cattleClassName) {
var tempVar = campName.name + "." + cattleClassName.name;
var tempNum = parseInt(req.body[tempVar]);
// console.log(tempNum);
if (tempNum) {
// console.log(req.body[tempVar]);
campCount.count[cattleClassName.name] = req.body[tempVar];
emptyCount = false;
} else {
campCount.count[cattleClassName.name] = 0;
}
});
if (!emptyCount) {
campCount.save(function(err) {
if (err) {
return next(err);
}
});
campCountArray.push(campCount);
}
});
console.log("CampCountArray");
console.log(campCountArray);
weekCount.campCounts = campCountArray;
});
});
// ****************************************************************
// Check if Week Count with same date already exists.
WeekCount.findOne({ dateOfCount: req.body.dateOfCount }).exec(function(
err,
found_weekCount
) {
if (err) {
console.log("ERROR findone " + err);
return next(err);
}
if (found_weekCount) {
// Week count exists, redirect to its detail page.
console.log("FOUND");
res.redirect(found_weekCount.url);
} else {
console.log("NOT FOUND");
// weekCount.markModified('campCounts');
weekCount.save(function(err) { // <---- does not save
if (err) {
console.log("ERROR SAVING: " + err);
return next(err);
}
console.log("weekCount saved");
console.log(weekCount);
// output below
// Week Count saved. Redirect to week count detail page.
// console.log(weekCount.campCounts);
res.redirect(weekCount.url);
});
}
});
}
}
];
Output from console.log:
GET /catalog/WeekCount/create 200 219.085 ms - 3782
NOT FOUND <------ count not a duplicate (OK)
CampCountArray
[ { count: { calf: 1, bull: 0, cow: 0, weaner: 0, ox: 0, heifer: 0 },
_id: 5d83720e2279011e90a1614b,
campName: 'Bloekom' },
{ count: { calf: 1, bull: 0, cow: 0, weaner: 0, ox: 0, heifer: 0 },
_id: 5d83720e2279011e90a1614c,
campName: 'Davel' },
{ count: { calf: 1, bull: 0, cow: 0, weaner: 0, ox: 0, heifer: 0 },
_id: 5d83720e2279011e90a1614d,
campName: 'Elfas' },
{ count: { calf: 1, bull: 0, cow: 0, weaner: 0, ox: 0, heifer: 0 },
_id: 5d83720e2279011e90a1614e,
campName: 'Groot kamp' } ]
weekCount saved
{ campCounts:
[ { count: [Object],
_id: 5d83720e2279011e90a1614b,
campName: 'Bloekom',
__v: 0 },
{ count: [Object],
_id: 5d83720e2279011e90a1614c,
campName: 'Davel',
__v: 0 },
{ count: [Object],
_id: 5d83720e2279011e90a1614d,
campName: 'Elfas',
__v: 0 },
{ count: [Object],
_id: 5d83720e2279011e90a1614e,
campName: 'Groot kamp',
__v: 0 } ],
_id: 5d83720e2279011e90a1614a,
dateOfCount: 2019-09-06T00:00:00.000Z,
__v: 0 }
from mongo:
{
"_id" : ObjectId("5d83720e2279011e90a1614a"),
"campCounts" : [ ], <---------------------- nothing here!
"dateOfCount" : ISODate("2019-09-06T00:00:00Z"),
"__v" : 0
}
the campCounts ARE in mongo (sample):
{
"_id" : ObjectId("5d83720e2279011e90a1614d"),
"count" : {
"calf" : 1,
"bull" : 0,
"cow" : 0,
"weaner" : 0,
"ox" : 0,
"heifer" : 0
},
"campName" : "Elfas",
"__v" : 0
}
but weekCount does not update. This is the problem.
I think your suspicion is correct that weekCount is saving before the CattleClass.find() callback has finished executing.
You could fix this with .then syntax:
CattleClass.find({}, "name").exec(function(err, list_cattleClasses) {
...
}).then( function () {
WeekCount.findOne({ dateOfCount: req.body.dateOfCount }).exec(function(
err, found_weekCount) {
...
}
})
you could also use ES6 async/await syntax, but your code would take quite a bit of rewriting because you can't use .exec() with await.
Both methods will ensure CattleClass.find() finishes executing before running WeekCount.findOne()
If you need more info there are lots of great posts on Stack Overflow addressing asynchronous code.
The below code works properly now.
Use of .then() instead of mixing callbacks and promises.
Thanks for the help!
exports.weekCount_create_post = [
validator
.body("dateOfCount", "Week Count Data Required")
.toDate()
.isLength({ min: 1 })
.trim(),
// Sanitize (escape) the name field.
validator.sanitizeBody("*").escape(),
// Process request after validation and sanitization.
(req, res, next) => {
var weekCountDetail = {
dateOfCount: req.body.dateOfCount
};
const errors = validator.validationResult(req);
if (!errors.isEmpty()) {
// There are errors. Render the form again with sanitized values/error messages.
console.log("ERRORS!s");
async.parallel(
{
camps: function(callback) {
Camp.find()
.sort("name")
.exec(callback);
},
cattleClasses: function(callback) {
CattleClass.find(callback);
}
},
function(err, results) {
if (err) {
return next(err);
}
res.render("weekCount_form", {
title: "There were Errors! New Week Count",
camps: results.camps,
cattleClasses: results.cattleClasses
});
}
);
return;
} else {
Camp.find({}, "name")
.exec()
.then(list_camps => {
return CattleClass.find({}, "name")
.exec()
.then(list_cattleClasses => {
return [list_camps, list_cattleClasses];
});
})
.then(qResult => {
list_camps = qResult[0];
list_cattleClasses = qResult[1];
var campCountArray = [];
list_camps.forEach(function(campName) {
var campCount = new CampCount({
campName: campName.name
});
var emptyCount = true;
list_cattleClasses.forEach(function(cattleClassName) {
var tempVar = campName.name + "." + cattleClassName.name;
var tempNum = parseInt(req.body[tempVar]);
if (tempNum) {
campCount.count[cattleClassName.name] = req.body[tempVar];
emptyCount = false;
} else {
campCount.count[cattleClassName.name] = 0;
}
});
if (!emptyCount) {
campCount.save(function(err) {
if (err) {
return next(err);
}
});
campCountArray.push(campCount);
}
});
weekCountDetail.campCounts = campCountArray;
return weekCountDetail;
})
.then(weekCountDetail => {
WeekCount.findOne({ dateOfCount: req.body.dateOfCount })
.exec()
.then(found_weekCount => {
if (found_weekCount) {
res.redirect(found_weekCount.url);
} else {
console.log("Not FOUND");
var weekCount = new WeekCount(weekCountDetail);
console.log("WEEKCOUNT3");
console.log(weekCount);
weekCount.save(err => {
if (err) {
return next(err);
}
res.redirect(weekCount.url);
});
}
})
.catch(err => {
console.log("error findOne " + err);
return next(err);
});
});
}
}
];

Using mongoose lean after saving

So I am trying to add a key to a returned post. But I can't seem to get lean() to work. How can I manipulate the returned post after save?
I was thinking maybe I need to add lean to my findById like this Post.findById(req.params.id).lean().then(). But that didn't work, plus that only makes the first initial post mutable. It will say
post.save is not a function
if I do it like Post.findById(req.params.id).lean().then() as well
I want to only return the object about to be sent back to the client, I do not want they key saved in the actual document.
Post.findById(req.params.id)
.then(post => {
if (
post.likes.filter(like => like.user.toString() === req.user.id)
.length === 0
) {
return res
.status(400)
.json({ notliked: "You have not yet liked this post" });
}
// Get remove index
const removeIndex = post.likes
.map(item => item.user.toString())
.indexOf(req.user.id);
// Splice out of array
post.likes.splice(removeIndex, 1);
// Save
post.save().then(post => {
post["liked"] = false; <-------
res.json(post);
});
})
edit
Post.findById(req.params.id)
.lean()
.then(post => {
if (
post.likes.filter(like => like.user.toString() === req.user.id)
.length === 0
) {
return res
.status(400)
.json({ notliked: "You have not yet liked this post" });
}
// Get remove index
const removeIndex = post.likes
.map(item => item.user.toString())
.indexOf(req.user.id);
// Splice out of array
post.likes.splice(removeIndex, 1);
post["liked"] = false;
res.json(post);
// Save
post.save();
})
gives error
post.save is not a function
You can simply do this by searching for the req.user.id inside the indexOf likes array
Post.findOne({ _id: req.params.id }).lean().then((post) => {
if (post.likes.indexOf(req.user.id) !== -1) {
post.isLiked = true
}
post.isLiked = false
res.json(post)
})
Far better with the aggregation
Post.aggregate([
{ "$match": { "_id": mongoose.Types.ObjectId(req.user.id) }},
{ "$addFields": {
"isLiked": { "$in": [mongoose.Types.ObjectId(req.user.id), "$likes"] }
}}
])
EDIT :- If you want to update document then use update query
Post.findOneAndUpdate(
{ _id: req.params.id },
{ $pull: { likes: { user: req.user.id } }},
{ new: true }
).then((post) => {
res.json(post)
})
Post Schema for likes
...
likes: [
{
user: {
type: Schema.Types.ObjectId,
ref: "users"
}
}
]
...

mongodb model contain changed on calling a function levelQuestion

Here is the code for schema
schema stores questions for a particular course and which contains chapter and there question
questions: [
{
Chapter: String,
chques: [
{
description: String,
questions: [
{
question: String,
options: [String],
answer: Number,
Explanation: String,
code: { type: String, default: null },
images: [{ type: String, default: null }],
level: String
}
]
}
]
}
],
Here is the code for route
Router.get(
"/queformock/:course_id",
passport.authenticate("jwt", { session: false }),
(req, res) => {
Courses.findOne({ _id: req.params.course_id })
.lean()
.exec()
.then(course => {
if (!course) res.status(404).json({ course: "course not found" });
else {
let coursepass = Object.assign({}, course);
console.log("coursepass1: ", coursepass); //before calling levelQuestion it output as expected
let level2 = levelQuestion(coursepass, "medium");
console.log("coursepass2: ", coursepass);
let level3 = levelQuestion(coursepass, "hard");
console.log("coursepass3: ", coursepass);
res.json(level2);
}
});
}
);
Here is the levelQuestion function code
function levelQuestion(coursed, type) {
let arr = [];
coursed.questions.forEach(item => {
item.chques.forEach(i => arr.unshift(i));
});
arr.forEach(item => {
_.remove(item.questions, i => {
return i.level !== type;
});
});
_.remove(arr, item => {
return item.questions == false;
});
return arr;
}
now the problem is on every function call of levelQuestion coursepass is changed...why??

like/dislike mongodb using bulk

let bulk = Card.collection.initializeOrderedBulkOp();
// if user doesn't exist in array
bulk.find({
'_id': mongoose.Types.ObjectId(card_id),
'likedBy': { '$ne': mongoose.Types.ObjectId(user_id) }
}).updateOne({
'$inc': { 'likes': 1 },
'$push': { 'likedBy': mongoose.Types.ObjectId(user_id) }
});
// if user exists in array
bulk.find({
"_id": mongoose.Types.ObjectId(card_id),
"likedBy": mongoose.Types.ObjectId(user_id)
}).updateOne({
"$inc": { "likes": -1 },
"$pull": { "likedBy": mongoose.Types.ObjectId(user_id) }
});
bulk.execute(function(response) {
console.log(response);
return res.json({
'state': true,
'msg': 'Successful',
})
});
The above is supposed to behave by incrementing or decrementing the likes field if the user id exists in the likedBy array.
However, both functions run, thus the last of the bulk gets to be the last action done. In the above, the end result is always zero.
I suspect the query matches a document always, thus the .updateOne() parts run on all.
Here's the schema:
var CardSchema = new Schema({
slug: {
type: String,
lowercase: true,
index: true
},
title: String,
content: String,
createdAt: {
type: Date,
default: Date.now,
},
updatedAt: {
type: Date,
},
options: [],
likedBy: [],
likes: Number,
createdBy: String,
featured: Boolean,
});
Is there a better mongo way to do the like/dislike thing?
Going with this for now. Too verbose, but works. I've created a like and dislike button separately in the UI, which calls two independent functions, but to same endpoint, with endpoint rigged like this:
let like = req.body.like;
// if request is a like
if (like) {
Card.update({
'_id': mongoose.Types.ObjectId(card_id),
'likedBy': { '$ne': mongoose.Types.ObjectId(user_id) }
}, {
'$inc': { 'likes': 1 },
'$push': { 'likedBy': mongoose.Types.ObjectId(user_id) }
}, function(err) {
if (err) {
console.log(err);
return res.json({
'state': false,
'msg': err
})
}
return res.json({
'state': true,
'msg': 'Liked',
})
})
} else if (!like) { // if request is dislike
Card.update({
'_id': mongoose.Types.ObjectId(card_id),
'likedBy': mongoose.Types.ObjectId(user_id)
}, {
'$inc': { 'likes': -1 },
'$pull': { 'likedBy': mongoose.Types.ObjectId(user_id) }
}, function(err,) {
if (err) {
console.log(err);
return res.json({
'state': false,
'msg': err
})
}
return res.json({
'state': true,
'msg': 'Disliked',
})
})
}
Then something like this makes the request,
likeCard(card_id: string, like: boolean) {
let param = {
card_id: card_id,
like: like
};
return this.http.post(AppSettings.API_ENDPOINT + '/card/like', JSON.stringify(param), { headers: this.headers })
.map((res) => {
return res
})
}