Mongodb Schema issue - node.js

Here i am using Nodejs application to get JSON response from external API.I need to capture few key-value pair of this response and need to save it MongoDB.
I am getting the response properly, but i am unable to save the data in database.
Requirement:
Each time i get this response from External server , i need to save it in table by rewriting any documents if already exists in this collection. Here i have nearly 7 array items in json response , i need to save corresponding key value pair from all of the items automatically .
Model:
var mongoose = require('mongoose');
const getAllUsersDataSchema = new mongoose.Schema({
userRefID:[] ,
userName:[],
divisionId: [{}],
divisionName:[{}],
emailId :[{}],
})
module.exports = getAllUsers = mongoose.model('getAllUsers',getAllUsersDataSchema );
**API Call where i am capturing external API response:**
const express = require('express');
const router = express.Router();
const request = require('request');
const config = require('../config');
const fs = require('fs');
const getAllUsers = require ('../db/getAllUsersListmodel');
var mongoose = require('mongoose');
mongoose.connect ('mongodb://localhost/testdb',{ useUnifiedTopology: true , useNewUrlParser: true });
router.get('/', (req, res) => {
// token in session -> get user data and send it back to the Angular app
var data =fs.readFileSync('../teamlist.txt', {encoding:'utf8'} )
console.log(data);
if (data) {
request(
{
method: 'GET',
url: 'https://api.mypurecloud.com/api/v2/users',
headers: {
'Authorization': 'Bearer ' + data
}
},
// callback
(error, response, body) => {
let userInfoResponse = JSON.parse(body);
res.send(userInfoResponse);
console.log(userInfoResponse.entities.length)
console.log(userInfoResponse.entities[0].division.id)
getAllUsers.create({
userRefID : userInfoResponse.entities.id,
userName: userInfoResponse.entities.name,
divisionId: userInfoResponse.entities.division.id,
divisionName:userInfoResponse.entities.division.name,
emailId:userInfoResponse.entities.primaryContactInfo.address
}, (error,post)=>{
console.log(error,post);
});
}
);
}
// no token -> send nothing
else {
res.send("Token Not Present - Kindly login in back");
}
//console.log(req.session.token);
});
Data is saving in DB but not getting any array data saved in to it.
{
"_id" : ObjectId("5fd998d61439a434983702cd"),
"userRefID" : [ ],
"userName" : [ ],
"__v" : 0
}
This is exact API JSON response i am trying to save it in DB and use it for future references:
{
"entities": [
{
"id": "07f426ff-506f-4e5e-afdb-2c7397edac61",
"name": "EPS Purecloud Support",
"division": {
"id": "36852a81-ad7f-4c71-a1cd-7f431c05179f",
"name": "",
"selfUri": "/api/v2/authorization/divisions/36852a81-ad7f-4c71-a1cd-7f431c05179f"
},
"chat": {
"jabberId": "5dcc25e1db8c7e19238a287d#cognizant3.orgspan.com"
},
"email": "eps#genesys.com",
"primaryContactInfo": [
{
"address": "eps#genesys.com",
"mediaType": "EMAIL",
"type": "PRIMARY"
}
],
"addresses": [],
"state": "active",
"username": "eps#genesys.com",
"version": 3,
"acdAutoAnswer": false,
"selfUri": "/api/v2/users/07f426ff-506f-4e5e-afdb-2c7397edac61"
},
{
"id": "c5ce06dc-6265-4d16-be18-f5fc5a918295",
"name": "Generic",
"division": {
"id": "36852a81-ad7f-4c71-a1cd-7f431c05179f",
"name": "",
"selfUri": "/api/v2/authorization/divisions/36852a81-ad7f-4c71-a1cd-7f431c05179f"
},
"chat": {
"jabberId": "5ebab3dba6686314f6913b98#cognizant3.orgspan.com"
},
"email": "integration-generic-a03293c0-945d-11ea-a64c-ebeb45b9d295#webhook.com",
"primaryContactInfo": [
{
"address": "integration-generic-a03293c0-945d-11ea-a64c-ebeb45b9d295#webhook.com",
"mediaType": "EMAIL",
"type": "PRIMARY"
}
],
"addresses": [],
"state": "active",
"username": "integration-generic-a03293c0-945d-11ea-a64c-ebeb45b9d295#webhook.com",
"version": 2,
"acdAutoAnswer": false,
"selfUri": "/api/v2/users/c5ce06dc-6265-4d16-be18-f5fc5a918295"
},
{
/** 3rd User *********/
}
{
/** 4th User *********/
}
],
"pageSize": 25,
"pageNumber": 1,
"total": 7,
"firstUri": "/api/v2/users?pageSize=25&pageNumber=1",
"selfUri": "/api/v2/users?pageSize=25&pageNumber=1",
"lastUri": "/api/v2/users?pageSize=25&pageNumber=1",
"pageCount": 1
}

Entities is an array of objects, but you are trying to refer to its properties as an object:
userRefID : userInfoResponse.entities.id, // but "entities": [ {"id":"...", "name":"..."} ],
userName: userInfoResponse.entities.name,
You have to collect the data in a loop, and only then insert it into the database:
const usersArray = userInfoResponse.entities.map(el => ({
userRefID : el.id,
userName: el.name,
divisionId: el.division.id,
divisionName: el.division.name,
emailId: el.primaryContactInfo[0].address
}));
getAllUsers.insertMany(usersArray)

Related

Remove object from nested array in MongoDB using NodeJS

I can see that this question should have been answered here, but the code simply doesn't work for me (I have tried multiple, similar variations).
Here is my data:
[{
"_id": {
"$oid": "628cadf43a2fd997be8ce242"
},
"dcm": 2,
"status": true,
"comments": [
{
"id": 289733,
"dcm": 2,
"status": true,
"clock": "158",
"user": "Nathan Field",
"dept": "IT",
"department": [],
"dueback": "",
"comment": "test 1"
},
{
"id": 289733,
"dcm": 2,
"status": true,
"clock": "158",
"user": "Nathan Field",
"dept": "IT",
"department": [],
"dueback": "",
"comment": "test 2"
}
],
"department": [],
"dueback": ""
}]
And here is my code
const deleteResult = await db.collection('status').updateOne(
{ "dcm": comments.dcm },
{ $pull: { "comments": { "id": comments.id } } },
{ upsert: false },
{ multi: true }
);
Absolutely nothing happens...
So the issue ended up being something to do with running multiple update operations within one function. I have a database connection function like this:
const withDB = async (operations, res) => {
try {
const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true });
const db = client.db('collection');
await operations(db);
client.close();
} catch (error) {
res.status(500).json({ message: 'Error connecting to db', error });
}
}
And then I call this by using:
withDB(async (db) => {
await db.collection('status').updateMany(
{ "dcm": comments.dcm },
{ $pull: { "comments": { "id": comments.id } } },
{ multi: true }
);
});
The issue occurred it would seem because I had two of these update operations within one withDB function. I have multiple operations in other instances (update item, then fetch collection), but for some reason this caused an issue.
I created a separate call to the withDB function to perform the '$pull' (delete) request, and then updated the array with the new comments.
To check that there was nothing wrong with my actual query, I used Studio3T's IntelliShell feature. If I'd done that sooner I would saved myself a lot of time!

How to retrieve metadata from Stripe session object NodeJS

I am trying to pass a UID and purchase ID with Stripe Checkout session object (using metadata). Generating the session ID on my server attaching the metadata works very fine. Stripe also POSTs everything correctly to my webhook server. The problems occurs while retrieving the metadata from the session object POSTed by Stripe.
Here is the error I get
TypeError: Cannot read property 'metadata' of undefined at /app/app.js:35:32
Here is the session obj posted by Stripe-
{
"id": "evt_1GRC7lAfcfWZXl7jQ3VzNo4y",
"object": "event",
"api_version": "2019-10-17",
"created": 1585292221,
"data": {
"object": {
"id": "cs_test_gLsHqtF8XhB3C3DlWKcLtNdTitp0St8ju5qgJgl6tHrMxxWvju9gb9Li",
"object": "checkout.session",
"billing_address_collection": null,
"cancel_url": "https://andropaym.firebaseapp.com/fail.html",
"client_reference_id": null,
"customer": "cus_GzASi1Klpydh8x",
"customer_email": null,
"display_items": [
{
"amount": 37500,
"currency": "inr",
"custom": {
"description": "Carefully modified Linux Distro Bundle for Android.",
"images": null,
"name": "Modded OS Bundle"
},
"quantity": 1,
"type": "custom"
}
],
"livemode": false,
"locale": null,
"metadata": {
"uid": "EB1m6nAOTVNcQhHO2O7COspap8y1",
"payID": "GPA.5620-9852-7063-44324"
},
"mode": "payment",
"payment_intent": "pi_1GRC7EAfcfWZXl7jhixrWHRS",
"payment_method_types": [
"card"
],
"setup_intent": null,
"shipping": null,
"shipping_address_collection": null,
"submit_type": null,
"subscription": null,
"success_url": "https://andropaym.firebaseapp.com/success.html"
}
},
"livemode": false,
"pending_webhooks": 4,
"request": {
"id": null,
"idempotency_key": null
},
"type": "checkout.session.completed"
}
Here is my webhook code -
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const stripe = require('stripe')('sk_test_xxxx');
const endpointSecret = 'whsec_xxxx';
// set the port of our application
// process.env.PORT lets the port be set by Heroku
var port = process.env.PORT || 8080;
app.post('/', bodyParser.raw({type: 'application/json'}), (request, response) => {
const sig = request.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret);
} catch (err) {
return response.status(400).send(`Webhook Error: ${err.message}`);
}
function handleCheckoutSession(uid) {
// Here we are getting the session obj and we can process it to check for the things we need
console.log("UID is " + uid);
}
// Handle the checkout.session.completed event
if (event.type === 'checkout.session.completed') {
const session = event.data.object;
let uid = request.data.metadata.uid;
// Fulfill the purchase...
handleCheckoutSession(uid);
}
// Return a response to acknowledge receipt of the event
response.json({received: true});
});
app.listen(port, function () {
console.log('Our app is running on http://localhost:' + port);
});
module.exports = app;
The code works fine without the metadata being parsed
More code links:
1. Highlighted error webhook code - https://gist.github.com/imprakharshukla/1e2315615983e0e9d492d2288e159832#file-webhook_backend-js-L40
You need to use the object returned by stripe.constructEvent, not the request body.
Change
let uid = request.data.metadata.uid;
to
let uid = session.metadata.uid
and it should work as expected.

"data" field not populated in axios response from express server

I am trying to access data from a nodejs server using Express on the server and Axios on the backend.
This is the endpoing I am trying to reach: http://gentle-bastion-49098.herokuapp.com/api/filters
As you can see it actually returns data when you navigate to it. But when I try to access it using the following code:
const BASE_URL = 'http://gentle-bastion-49098.herokuapp.com/api'
function getFilterData () {
const url = `${BASE_URL}/filters`
return axios.get(url)
}
getFilterData()
.then(function (response) {
console.log('filter', response)
})
.catch(err => {
alert('Could not get filters ' + err.message.toString())
})
I get this response with the "data" field being unpopulated where I'm expecting it to contain the JSON you see in the URL.
{
"data": "",
"status": 200,
"statusText": "OK",
"headers": {},
"config": {
"url": "http://gentle-bastion-49098.herokuapp.com/api/filters",
"method": "get",
"headers": {
"Accept": "application/json, text/plain, */*"
},
"transformRequest": [null],
"transformResponse": [null],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1
},
"request": {}
}
Here is the back end code
const express = require('express');
const app = express();
const async = require('async');
const request = require('request');
const http = require('http');
const EventSource = require('eventsource');
const port = process.env.PORT || 8080;
const bodyParser = require('body-parser');
const jsonParser = bodyParser.json()
app.get('/api/filters', function(req, res) {
let filtersResponse = {
"ID": "CONV_DATA#IVA",
"ApplicationName": "InterationsView",
"Type": "FILT_DETAIL",
"filters": [{
"Name": "ChannelType",
"Values": uniqueFilters.ChannelType,
},
{
"Name": "sessionType",
"Values": uniqueFilters.sessionType,
},
{
"Name": "Direction",
"Values": uniqueFilters.Direction,
},
{
"Name": "Status",
"Values": uniqueFilters.Status,
},
{
"Name": "statusReason",
"Values": uniqueFilters.statusReason,
},
],
"minDuration": uniqueFilters.minDuration,
"maxDuration": uniqueFilters.maxDuration,
"minData": "2019-08-29T22:28:47.029UTC",
"maxDate": "2019-08-29T22:28:49.578UTC"
};
// Respond with filters
res.json(filtersResponse);
});
Any ideas as to why the data field is unpopulated even though when accessed through browser or postman it returns the desired data? Is it a problem with the back end or the way the request is being made? Thanks.
I have also enabled cross-orgin resource sharing on my browser. Not doing so results in an error
I am not clear whether you are not getting axios response or response from your node server. If you have problem in getting axios response here is the code.
I have used request npm for making a get request.
const request = require('request');
apiUrl = "http://gentle-bastion-49098.herokuapp.com/api/filters"
request.get(
{
url: apiUrl,
json: true
},
function (error, response, body) {
if (error) {
console.log("Error Occurred :", error);
}
console.log("Response Data :", body)
}
);
The above code will give you response as :
{
"ID":"CONV_DATA#IVA",
"ApplicationName":"InterationsView",
"Type":"FILT_DETAIL",
"filters":[
{
"Name":"ChannelType",
"Values":[
"Phone",
"Web-Chat",
"Google-Assistant"
]
},
{
"Name":"sessionType",
"Values":[
"nlu-voice",
"nlu-text"
]
},
{
"Name":"Direction",
"Values":[
"In"
]
},
{
"Name":"Status",
"Values":[
"Complete",
"Started"
]
},
{
"Name":"statusReason",
"Values":[
"END"
]
}
],
"minDuration":9.7,
"maxDuration":154.2,
"minData":"2019-08-29T22:28:47.029UTC",
"maxDate":"2019-08-29T22:28:49.578UTC"
}
which is same as what you get in browser when you visit the link http://gentle-bastion-49098.herokuapp.com/api/filters
If you are using axios the code will be :
const axios = require('axios');
apiUrl = "http://gentle-bastion-49098.herokuapp.com/api/filters"
axios.get(apiUrl)
.then(function (response) {
console.log("Response Data :", response.data);
})
.catch(function (error) {
console.log("Error Occurred :", error);
})
and it will give same response as above.
Even your written code is giving response :
Try with these changes:
getFilterData().then(response => {
console.log('filter', response.data)
})
.catch(err => {
alert('Could not get filters ' + err.message.toString())
})
In your server code, send the response back to client using res.send() as shown below:
app.get('/api/filters', function(req, res) {
let filtersResponse = {
"ID": "CONV_DATA#IVA",
"ApplicationName": "InterationsView",
"Type": "FILT_DETAIL",
"filters": [{
"Name": "ChannelType",
"Values": uniqueFilters.ChannelType,
},
{
"Name": "sessionType",
"Values": uniqueFilters.sessionType,
},
{
"Name": "Direction",
"Values": uniqueFilters.Direction,
},
{
"Name": "Status",
"Values": uniqueFilters.Status,
},
{
"Name": "statusReason",
"Values": uniqueFilters.statusReason,
},
],
"minDuration": uniqueFilters.minDuration,
"maxDuration": uniqueFilters.maxDuration,
"minData": "2019-08-29T22:28:47.029UTC",
"maxDate": "2019-08-29T22:28:49.578UTC"
};
// Respond with filters
res.send(
filtersResponse
)
});

Null value in model.findById when I make a get request [mongodb]

Problem
Hi dev,
I have the problem that when I try to make a get request to the series by id it shows me null.
I have noticed from the Atlas Mongos platform that I created the collection but it does not show me the data, only the structure of the scheme shows me
Function.js
const fs = require('fs');
const fetch = require('node-fetch');
const BASE_URL = " http://localhost:8081/api/v1/"
async function getSeries() {
return new Promise((resolve , reject) =>{
setTimeout(() => {
const res = require('./simple_database/series/1.json' , 'utf8');
resolve(res)
}, 1000);
})
}
module.exports = {
getSeries
}
Router
The route allseries allows me to access all the content. What I want to do is pass that content to the SeriesModel, maybe it is there where I have the problem that the data is not being inserted correctly.
In the route series/:id is where the null value is returning to me
const express = require('express');
const router = express.Router();
const f = require('./function');
const SeriesModel = require('./models/series');
router.get('/allseries', (req, res) => {
f.getSeries().then((series) =>{
res.status(200).json({
series
})
}).then((doc) =>{
SeriesModel.insertMany(doc , function(err , docs){
if(err){
console.error(err)
}else{
console.log(docs);
console.info('%d serie were successfully stored.', docs.length);
}
})
})
});
router.get('/series/:id' , (req , res , next) =>{
const id = req.params.id;
SeriesModel.findById(id)
.exec()
.then((doc) =>{
console.log("From database " , doc);
res.status(200).json(doc)
}).catch((err) =>{
console.error(err);
res.status(500).json({error: err})
})
})
module.exports = router;
Model/series.js
const mongoose = require('mongoose');
const serieSchema = mongoose.Schema({
"_id": {
"$oid": {
"type": "ObjectId"
}
},
"series_id": {
"type": "String"
},
"aggregateRating": {
"reviewCount": {
"type": "Number"
},
"ratingCount": {
"type": "Number"
},
"#type": {
"type": "String"
},
"ratingValue": {
"type": "Number"
}
},
"episodes": {
"1x": {
"07 Ghost": {
"type": [
"Mixed"
]
}
}
},
"metadata": {
"description": {
"type": "String"
},
"url": {
"type": "String"
},
"image": {
"type": "String"
},
"type": {
"type": "String"
},
"id": {
"type": "String"
},
"name": {
"type": "String"
}
},
"1x": {
"07 Ghost": {
"type": [
"Mixed"
]
}
}
});
module.exports = mongoose.model("cr_series" , serieSchema);
It is because findById takes it's parameter in form of object like this
SeriesModel.findById({_id:id})
You need to tell your query to which json object you want to match your incoming object.

Rejecting mapping update error in firebase when pushing data to elastic search index

I am trying to use Firebase cloud functions to push data to my ElasticSearch index and am experiencing some error in the Firebase. Where could the problem be?
Here is my index.js function code
const functions = require('firebase-functions');
const request = require('request-promise')
exports.indexPostsToElastic = functions.database.ref('/posts/{post_id}')
.onWrite((change,context) =>{
let postData = change.after.val();
let post_id = context.params.post_id;
console.log('Indexing post',postData);
let elasticSearchConfig = functions.config().elasticsearch;
let elasticSearchUrl = elasticSearchConfig.url + 'posts/' + post_id;
let elasticSearchMethod = postData ? 'POST' : 'DELETE';
let elasticSearchRequest = {
method:elasticSearchMethod,
url: elasticSearchUrl,
auth:{
username : elasticSearchConfig.username,
password : elasticSearchConfig.password,
},
body: postData,
json : true
};
return request(elasticSearchRequest).then(response => {
return console.log("ElasticSearch response", response);
})
});
And below is the error am receiving in Firebase
StatusCodeError: 400 - {"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"Rejecting mapping update to [posts] as the final mapping would have more than 1 type: [_doc, -LcVpBay0SLV3c6fnpgt]"}],"type":"illegal_argument_exception","reason":"Rejecting mapping update to [posts] as the final mapping would have more than 1 type: [_doc, -LcVpBay0SLV3c6fnpgt]"},"status":400}
at new StatusCodeError (/user_code/node_modules/request-promise/node_modules/request-promise-core/lib/errors.js:32:15)
Here is my index code in postman
{
"mappings":{
"properties":{
"city":{
"type": "text"
},
"contact_email":{
"type": "text"
},
"country":{
"type": "text"
},
"description":{
"type": "text"
},
"image":{
"type": "text"
},
"post_id":{
"type": "text"
},
"state_province":{
"type": "text"
},
"title":{
"type": "text"
}
}
}
}
As the error message suggests, multiple mapping types have been removed.
https://www.elastic.co/guide/en/elasticsearch/reference/6.0/removal-of-types.html

Resources