Can't retrieve embedded object from a MongoDB document - MERN stack - node.js

I am using the MERN stack for my current project. So I am facing this problem:
Let's say that I have the following document in MongoDB :
{
name: "Tesla Inc.",
category: "Automotive",
contact: {
state : {
name: "Texas",
city: "Austin",
address: {
streetName: "Tesla Road",
number: '1'
}
}
}
}
What I get as response after using findOne({ name : "Tesla"}) is :
{_id: '637e4397f6723844191aa03d', name: 'Tesla', category:
'Automotive', contact: {…}}
As you can see contact object is undefined
Follows my coding process
This is my Express route for quering the database :
storeRoutes.route("/enterprise").get(function (req, res) {
let db_connect = dbo.getDb("res");
const query = { name : "Tesla"};
db_connect
.collection("stores")
.findOne(query,function (err, result) {
if (err) throw err;
res.json(result);
});
});
Result: After typing browser url http://localhost:5000/enterprise returns the expected value:
{"_id":"637e4397f6723844191aa03d","name":"Tesla","category":"Automotive","contact":{"state":{"name":"Texas","city":"Austin","address":{"streetName":"Tesla Road","number":"1"}}}}
This a Retriever Data Function that returns the data object:
function GetEnterprise() {
const [store, setStore] = useState({
})
useEffect(() => {
async function fetchData() {
const response = await fetch(`http://localhost:5000/enterprise`);
if (!response.ok) {
const message = `An error has occurred: ${response.statusText}`;
window.alert(message);
return;
}
const record = await response.json();
if (!record) {
// window.alert(`Record with id ${id} not found`);
window.alert(`Record with id not found`);
return;
}
setStore(record);
}
fetchData();
return;
}, [1]);
//debugging
console.log('tesla: ' + store);
window.store = store;
let res_json = JSON.stringify(store);
console.log('res_json :' + res_json);
return store;
}
Result:
Before GetEnterprise() function returns store I have added these 4 lines of code for debugging:
console.log('tesla: ' + store);
window.store = store;
let res_json = JSON.stringify(store);
console.log('res_json :' + res_json);
1st line logs [object Object] which is not that informative for what I am getting back as a response.
So I came up with 2nd line which enables to debug directly from the browser console.
After I type store my console logs:
{_id: '637e4397f6723844191aa03d', name: 'Tesla', category: 'Automotive', contact: {…}}
So my contact object is missing(undefined).
Now fun fact is the 3rd and 4rd lines :
let res_json = JSON.stringify(store);
console.log('res_json :' + res_json);
My console logs the whole object as expected:
{"_id":"637e4397f6723844191aa03d","name":"Tesla","category":"Automotive","contact":{"state":{"name":"Texas","city":"Austin","address":{"streetName":"Tesla Road","number":"1"}}}}
Which is really weird.
I guess it has something to do with the async and await functions. But I am not sure.
What am I doing wrong?
Any suggestions ..?

Related

google calenderID nodejs doesn't work with specified CalendarID

I would like to use a google calendar, if I choose the calendar ID not as primary but with the specified one, I get an error message in line 46 (const eventsArray = res.data.calendars.calID.busy). The Error message looks like this (node:49993) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'calendar' of undefined. So basicly, i believe, it can't read the calender ID, can enyone help me to find my fault?
const { google } = require('googleapis');
const { OAuth2 } = google.auth;
const oAuth2Client = new OAuth2(
'id_works_with_primary_calender',
'key_works_with_primary_calender'
)
oAuth2Client.setCredentials({
refresh_token:
'works_with_primary',
})
const calendar = google.calendar( { version: 'v3', auth: oAuth2Client } );
const eventStartTime = new Date()
eventStartTime.setDate(eventStartTime.getDay() + 2)
const eventEndTime = new Date()
eventEndTime.setDate(eventEndTime.getDay() + 2)
eventEndTime.setMinutes(eventEndTime.getMinutes() + 45)
const event = {
summary: 'Meet with David',
location: '295 California St, San Francisco, CA 94111',
description: 'Meeting with David to talk about the new client Project and drink some stuff',
colorId: 1,
start: {
dateTime: eventStartTime,
timeZone: 'Europe/Zurich',
},
end: {
dateTime: eventEndTime,
timeZone: 'Europe/Zurich',
},
}
calendar.freebusy.query( {
resource: {
timeMin: eventStartTime,
timeMax: eventEndTime,
timeZone: 'Europe/Zurich',
items: [ { id: 'gd3q30fhkprf0ubsk3pnqkc64k#group.calendar.google.com' } ],
},
}, (err, res) => {
if (err) return console.error('Free Busy Query Error: ', err)
//Here is the error
const eventsArray = res.data.calendars.gd3q30fhkprf0ubsk3pnqkc64k#group.calendar.google.com.busy
if(eventsArray.length === 0)
return calendar.events.insert( {
calendarId: 'gd3q30fhkprf0ubsk3pnqkc64k#group.calendar.google.com',
resource: event,
},
err => {
if (err) return console.error('Calender Event Creation: ' + err)
return console.log('Event Created: ' + event)
})
return console.log("I'm Busy")
})
Issue:
The problem seems to be that the id includes several dots, and the program thinks these are used to access nested properties. Because of this, it is looking for the property calendar of the id gd3q30fhkprf0ubsk3pnqkc64k#group and, of course, it's not finding it, because the correct id is gd3q30fhkprf0ubsk3pnqkc64k#group.calendar.google.com.
Solution:
Therefore, assuming that this id is getting returned by res.data.calendars, the problem should be solved by changing the syntax with which you are accessing the key property, from dot notation to bracket notation.
That is to say, replace this:
const eventsArray = res.data.calendars.gd3q30fhkprf0ubsk3pnqkc64k#group.calendar.google.com.busy
With this:
const eventsArray = res.data.calendars["gd3q30fhkprf0ubsk3pnqkc64k#group.calendar.google.com"].busy
Reference:
Property accessors

nested map() and find() do not work in express + mongoose but work in codesandbox

I got a route in express that get 2 different array of object from mongoDb and then return a new "contributions" array after i've added some data into it from "projectAll"
Here is one contributions object:
{
_id: "5f5b095f01ba8e40769f7301",
libId: "5f5a7a7701ba8e40769f72fb",
totalPaidAmount: 10000,
transactionId: "pi_1HQ4hVGmJhXXrXOXnr0pkXkv",
cart: [
{
_id: "5f5b095f01ba8e40769f7302",
amount: 5000,
projectId: "5f5b086601ba8e40769f72fe"
},
{
_id: "5f5b095f01ba8e40769f7303",
amount: 5000,
projectId: "5f5b08ae01ba8e40769f7300"
}
],
__v: 0
}
And one projectAll object:
{
projectCover: { id: "211290" },
title: "My title 2",
funded: 11000,
description: "Desc",
_id: "5f5b08ae01ba8e40769f7300",
libId: "5f5a7a7701ba8e40769f72fb",
__v: 0
}
I need to add projectAll.title and projectAll.projectCover into each contributions.cart objects.
To do so I match contribution.cart.projectId with projectAll._id.
router.get("/contributions/:id", async (req, res) => {
const id = req.params.id
try {
const contributions = await Contribution.find({id})
const projectAll = await Project.find({id})
const updatedContribution = contributions.map((contribution) => {
// Go through each cart of each contribution
const updatedCart = contribution.cart.map((cartItem) => {
// Find matching project
const matchingProject = projectAll.find((project) => {
// project OK =====> console.log(project)
// projectAll OK =====> console.log(projectAll)
// cartItem OK =====> console.log(cartItem)
return project._id === cartItem.projectId;
});
// Here return undefined =====> console.log(matchingProject)
const {projectCover, title} = matchingProject
return {...cartItem, projectCover, title
}
})
return { ...contribution, cart: updatedCart
}
})
res.send(updatedContribution)
} catch (err) {
res.status(500).send(err)
}
this code work perfectly in my codeSandBox : https://codesandbox.io/s/contribution-map-projects-vhv8z?file=/src/index.js
But in my express + mongoose environment I get undefined for matchingProject (i added comments in the code to show from where I get unwanted result)
Does anybody know why it doesn't work ?
Thanks a lot !
EDIT: console.log(typeof project._id, typeof cartItem.projectId) return object object
whereas in codesandbox those are strings.
Since they are both ObjectIds you can use mongoose equals() functions - so project._id.equals(cartItem.projectId). You cannot compare them, cause you'd compare their object reference. So either the above function will work or project._id.toString() === cartItem.projectId.toString()

How to send query parameters with axios to backend

I am trying to send a string and number values upon hitting submit which is to be stored in a database collection (log collection).
I am making use of the MERN stack. I have tried sending it vis Axios, but when I console log the "req.params" in the backend, I get undefined. why am I not getting the typed in value of "order" at the backend? I am sure there is something I am not doing right, but I can figure it out. I need help.
handleSubChange(id, quantity){
// these lines of code below gets the inputted values and then subtracts from the total quantity
if ((parseInt(quantity) - parseInt(this.state.minus))<0) {
alert('The input value is too high.');
}else{
var nums = parseInt(quantity)-parseInt(this.state.minus);
// and just before I send the value of "nums" via Axios, I get the user to type in destination for the item and add the inputted value of "order" on the Axios URL
const order = prompt("Please enter item destination")
axios.get("/api/inventory/add_product/" + id + "/" + nums + "/" + parseInt(quantity) + "/" + order)
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
})
}
}
Here is the backend route
router.get("/add_product/:id/:num/:quantity/:order",(req,res) => {
var id = req.params.id;
var quantity = req.params.quantity;
//i then console log req.params.order, i get undefined
console.log(req.params.order)
// console.log('id----', id);
var num_mod = req.params.num;
var modified_count = parseInt(num_mod) - parseInt(quantity);
console.log('num_mod----', num_mod);
Inventory.findByIdAndUpdate(id,{quantity: parseInt(num_mod)},{new:true},function(err,inventory){
if (err){
console.log("err",err);
res.status(500).send(err);
} else {
console.log(inventory.name);
console.log(inventory.order)
const newLog = new Log({
name:inventory.name,
description:inventory.description,
price:parseInt(inventory.price),
quantity:parseInt(inventory.quantity),
modified_quantity: parseInt(modified_count),
order:inventory.order,
});
newLog.save(function(err, Log) {
if (err){
console.log(err);
} else{
console.log('add log success');
res.send(inventory);
}
});
}
});
});
Inventory model
const mongoose= require('mongoose');
//create Schema
const InventorySchema = new mongoose.Schema({
// _id: mongoose.Schema.Types.ObjectId,
name : { type: String, required: true },
description : { type: String, required: true },
price : { type: Number, required: true },
quantity : { type: Number, required: true },
supplier : String,
taxable : Boolean,
order:String,
// Create model from the schema
const Inventory = mongoose.model("Inventory", InventorySchema);
// Export model
module.exports = Inventory;
The issue is your backend route definition, which is missing a / before :order.
router.get("/add_product/:id/:num/:quantity:order",(req,res) => {
// ^ missing /
Change to:
router.get("/add_product/:id/:num/:quantity/:order",(req,res) => {
// ^ correct

Writing to MongoDB fails silently during Neo4j session.run() but works fine normally

The problem is that everything works fine in isolation, but as soon as I combine the Log.create(obj) into the Neo4j result stream, it stops working and what I assume is some Promise behaviour is eating all log information so I can't figure out why exactly it's not working or how to force it to display meaningful information.
I have been trying to diagnose this for the past 2 days, but I can't figure out why.
I have 2 files:
example.js and E1Logger/index.js
The logger file is simply the schema and models for a method that writes an object to MongoDB. It works fine if I comment out the bottom half of example.js.
I've tried probably like 20 different combinations of chaining promises, catching, done, exec, making it more asynchronous, making it more synchronous, and I can't seem to get any meaningful information.
I'm dying to know what is required to make it work.
example.js
//var config = require('./config');
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/major', error => { if (error) { console.error('ERROR: ' + error) }});
//mongoose.Promise = global.Promise;
var neo4j = require('neo4j-driver').v1;
var config = {};
config.neo4jHost = 'bolt://localhost:7687';
config.neo4jUser = 'neo4j';
config.neo4jPassword = 'garbagepassword';
var driver = neo4j.driver(config.neo4jHost, neo4j.auth.basic(config.neo4jUser, config.neo4jPassword));
var E1Logger = require('./E1Logger');
let newInfoLog = {
logType: 'INFO',
eventType: 'Purge Stale Invite',
result: 'Success',
invitedByUser: {
neo4jNodeID: 123,
name: 123 + ' ' + 321,
email: 123
},
purgedUser: {
neo4jNodeID: 123,
email: 123
},
createdAt: 123,
expirationAt: 123
};
let newErrorLog = {
logType: 'ERROR',
eventType: 'Purge Stale Invite',
result: 'Fail',
reason: 123,
attemptedQuery: 123,
};
E1Logger.info(newInfoLog);
E1Logger.error(newErrorLog);
// Calculate cutoff time for expired invites and form the Cypher Query
var currentTime = new Date().getTime();
var sliceTime = currentTime - 604800000; // 604800000 milliseconds in one week
var cypherQuery = 'MATCH (e:Person)-[r:INVITED_TO_APP]->(x) WHERE r.expirationAt<=\'' + sliceTime + '\' AND r.status=\'pending\' RETURN id(e) as invitedByUserId, e.given_name as invitedByUserFirstName, e.family_name as invitedByUserLastName, e.email as invitedByUserEmail, r.createdAt as createdAt, r.expirationAt as expirationAt, id(x) as purgedUserId, x.email as purgedUserEmail';
// Execute Purge Event
var session = driver.session();
session
.run(cypherQuery)
.then(function(result){
result.records.forEach(function(record) {
// Generate log for each expired invite
let newInfoLog = {
logType: 'INFO',
eventType: 'Purge Stale Invite',
result: 'Success',
invitedByUser: {
neo4jNodeID: record.get('invitedByUserId').low,
name: record.get('invitedByUserFirstName') + ' ' + record.get('invitedByUserLastName'),
email: record.get('invitedByUserEmail')
},
purgedUser: {
neo4jNodeID: record.get('purgedUserId').low,
email: record.get('purgedUserEmail')
},
createdAt: record.get('createdAt'),
expirationAt: record.get('expirationAt')
};
// Log result
console.log('PURGED: ' + JSON.stringify(newInfoLog));
E1Logger.info(newInfoLog);
});
session.close();
driver.close();
})
.catch(function(error) {
// Generate log for failed purge
let newErrorLog = {
logType: 'ERROR',
eventType: 'Purge Stale Invite',
result: 'Fail',
reason: error,
attemptedQuery: cypherQuery,
};
// Log result
console.log('ERROR: ' + JSON.stringify(newErrorLog));
E1Logger.error(newErrorLog);
//session.close();
//driver.close();
});
mongoose.disconnect();
E1Logger/index.js
const mongoose = require('mongoose');
// Define Info Log Schema
const InfoLogModel = mongoose.model('Infolog', new mongoose.Schema({
logType: String,
loggedAt: { type: Number, default: new Date().getTime() },
eventType: String,
result: String,
invitedByUser: {
neo4jNodeID: Number,
name: String,
email: String
},
purgedUser: {
neo4jNodeID: Number,
email: String
},
createdAt: Number,
expirationAt: Number
}));
// Define Error Log Schema
const ErrorLogModel = mongoose.model('Errorlog', new mongoose.Schema({
logType: String,
loggedAt: { type: Number, default: new Date().getTime() },
eventType: String,
result: String,
reason: String,
attemptedQuery: String,
}));
module.exports = {
// Define Info Log Model
info: function(eventData) {
InfoLogModel.create(eventData, (error, addedEvent) => {
if (error) throw error;
console.log('INFO: ' + addedEvent);
});
},
// Define Error Log Model
error: function(eventData) {
ErrorLogModel.create(eventData, (error, addedEvent) => {
if (error) throw error;
console.log('ERROR: ' + addedEvent);
});
}
};
I suspect the problem is at ErrorLogModel.create(eventData). I've never been able to get it to write to MongoDB from inside session.run(). A had a couple combinations that were showing something about a promise rejection, but that's as close as I got. I recall something like ErrorLogModel.create(eventData).catch( err => console.log('ok') ); made it do that.
Am I missing something about promises here? Why does functional code working code through Neo4j session.run().then() cause it to stop working? Is it maybe a bug I should report to Mongoose or Neo4j?

Node.JS cradle and couchDB assistance

I am a noob with Node.JS.
I am using CouchDB and Cradle.
In couchDB I have a database named 'test' and inside it I have a document named 'exercise'.
The document has 2 fields: "FullName" and "Age".
The code in order to save the data is as follows:
var cradle = require('cradle');
var connection = new(cradle.Connection)('http://127.0.0.1', 5984, {
auth: { username: 'toto_finish', password: 'password' }
});
var db = connection.database('test');
db.save('exercise', {
FullName: param_name, Age: param_age
}, function (err, res) {
if (err) {
// Handle error
response += ' SAVE ERROR: Could not save record!!\n';
} else {
// Handle success
response += ' SUCESSFUL SAVE: The record was saved in CouchDB!\n';
}
http_res.end(response);
});
this code works well and it saves the data to the CouchDB.
My problem is when I want to read the data.
The code that I wrote is:
var cradle = require('cradle');
var connection = new(cradle.Connection)('http://127.0.0.1', 5984, {
auth: { username: 'toto_finish', password: 'password' }
});
var db = connection.database('test');
db.view('exercise/all', {descending: true}, function(err, res)
{
console.log(res);
res.forEach(function (row) {
response = 'FullName: ' + row.FullName + '\n Age: ' + row.Age + '\n';
});
});
http_res.end(response);
when I am trying to print response, response is empty and I don't know what I am doing wrong. I know that it does not go inside the forEach loop but I don't understand why.
the console output is:
[ { id: 'exercise',
key: null,
value:
{ _id: 'exercise',
_rev: '1-7042e6f49a3156d2099e8ccb3cc7d937',
FullName: 'Toto Finish',
Age: '30' } } ]
Thanks in advance for any response or answer.
Try moving the http_res.send() call inside the callback provided to db.view - the anonymous function( err, res ) { }.
I'm not sure however about the .forEach statement, you'll only get the last value from your query in the response variable, you should look into that as well.
spotirca is right
The db.view function is async so http_res.end(response) gets called before the view returns any data.
You can prove this by returning the date in both the console.log and http_res.end
console.log(res, new Date())
and
http_res.end(response, new Date());
The http response will have the earlier date/Time.

Resources