Promise in cron job - javascript

I try to run the code without success.
Only the first call works in start of node.
Here is my current code:
const Product = require('../models/Product');
const Price = require('../models/Price');
const cron = require('node-cron');
const amazon = require('amazon-product-api');
const util = require('util');
const _ = require('underscore')
/**
* Cron job
* Tracking price
*/
exports.track = () => {
cron.schedule('* * * * *', () => {
const client = amazon.createClient({
awsId: process.env.AWS_ID,
awsSecret: process.env.AWS_SECRET,
assocId: process.env.AWS_TAG
});
Promise.all([Product.getAsin()])
.then(([asin]) => {
let listId = _.pluck(asin, '_id');
let listAsin = _.pluck(asin, 'asin');
if (asin.length === 0) {
return
}
client.itemLookup({
idType: 'ASIN',
itemId: listAsin,
domain: 'webservices.amazon.fr',
responseGroup: 'ItemAttributes,OfferFull,SalesRank'
}).then((results) => {
for(i=0; i<listId.length; i++){
results[i].id = listId[i];
}
for(res of results) {
Price.addPrice({
asin: res.ASIN[0],
product: res.id,
salePrice: res.Offers[0].Offer[0].OfferListing[0].Price[0].Amount[0],
})
}
console.log(listId);
Product.makeUpdate(listId);
}).catch(function(err) {
console.log(err);
console.log(util.inspect(err, true, null));
});
})
.catch((err) => {
console.log(err);
})
})
}
Requests to MongoDB are asynchronous.
Product
const mongoose = require('mongoose');
mongoose.Promise = Promise;
const _ = require('underscore');
const moment = require('moment');
const productSchema = new mongoose.Schema({
name: String,
domain: String,
originUrl: { type: String, unique: true },
check: { type: Number, default: 0 },
ean: String,
asin: String
}, { timestamps: true });
Object.assign(productSchema.statics, {
getAsin() {
return this.find(
{ updatedAt: { $lt: oneMin },
asin: { $ne: null }
}
).limit(10)
.select({ asin: 1 })
.exec()//.then((tuples) => _.pluck(tuples, 'asin'))
},
makeUpdate(id) {
console.log('list des ID updated => ' + id);
return this.update({ _id: { $in: id } }, { $inc : { "check": 1 } } , {multi: true}).exec();
}
});
const Product = mongoose.model('Product', productSchema);
module.exports = Product;
const oneMin = moment().subtract(1, 'minutes').format();
Also, since I'm absolutely new to JavaScript and Node.js in general, any best practices or general tips will be greatly appreciated! :)

Related

Cast to ObjectId failed for value XXX (type Object) at path \"depends_on\" for model \"Plan\"

I have an error message when I try to get a request from /api/subscriptions/5f108e96e55425340a7a7c6b of my project routes, this is the code from the get request:
index.js
const path = require('path');
const express = require('express');
const authRouter = require('./authRouter');
const apiRouter = require('./apiRouter');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const auth = require('../middleware/auth');
const { changeSubscriptionStatus } = require('../controllers/subscriptionController');
const mtto = false;
module.exports = function (app) {
app.use(bodyParser.json({ limit: '100kb' }));
app.use(cookieParser());
app.use('/auth', authRouter);
app.use('/api', apiRouter);
// routing static assets from build
app.use(express.static(path.resolve(__dirname, '../../build'), {
index: false
}));
// webpack hot reloading hack
if (process.env.NODE_ENV === 'hot') {
const webpack = require('webpack');
const webpackConfig = require('../../webpack.config');
const compiler = webpack(webpackConfig);
app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true, publicPath: webpackConfig.output.publicPath
}));
app.use(require('webpack-hot-middleware')(compiler));
}
app.post('/transactions/pending', changeSubscriptionStatus);
app.get('*', auth.optionalJwt, function (req, res, next) {
// console.log(req.originalUrl)
if (mtto) return res.sendFile(path.resolve(__dirname, '../../mtto/index.html'));
if (req.user) {
return res.sendFile(path.resolve(__dirname, '../../build/dashboard/index.html'));
}
return res.sendFile(path.resolve(__dirname, '../../build/public/index.html'));
});
};
subscription.js
const express = require('express');
const subscriptionRouter = express.Router();
const subscriptionController = require('../../controllers/subscriptionController');
const auth = require('../../middleware/auth');
const { Position } = require('../../constants/enums');
subscriptionRouter.get('/', subscriptionController.search);
subscriptionRouter.get('/byClient', auth.hasPosition(Position.ADMIN), subscriptionController.listByClient);
subscriptionRouter.post('/byEmail', subscriptionController.sendEmailInformation);
subscriptionRouter.post('/byemailactiv', subscriptionController.sendActivationCode)
subscriptionRouter.get('/:subscriptionId', subscriptionController.detail);
subscriptionRouter.get('/status/:subscriptionId', subscriptionController.statusDetail)
subscriptionRouter.post('/', auth.companyIsActive, subscriptionController.create);
subscriptionRouter.post(
'/renew',
auth.companyIsActive,
subscriptionController.renew
)
subscriptionRouter.delete('/:subscriptionId', subscriptionController.cancel);
subscriptionRouter.put('/:subscriptionId', auth.companyIsActive, subscriptionController.edit);
subscriptionRouter.post('/status', subscriptionController.editStatusSubscrition)
subscriptionRouter.post('/:subscriptionId/addon', auth.companyIsActive, subscriptionController.contractAddon);
subscriptionRouter.put('/:subscriptionId/addon/:planId', auth.companyIsActive, subscriptionController.editAddonSubscription);
subscriptionRouter.delete('/:subscriptionId/addon/:planId', subscriptionController.cancelAddonSubscription);
module.exports = subscriptionRouter;
And here is the detail function code from subscriptionController file:
subscriptionController.js
const Client = require("../models/client");
const Subscription = require("../models/subscription");
const defaults = require("../constants/defaults");
const { SubscriptionStatus, Position } = require("../constants/enums");
const Plan = require("../models/plan");
const Service = require("../models/service");
const Provider = require("../models/provider");
const Account = require("../models/account");
const notMissing = require("../util/notMissing");
const ApiError = require("../util/ApiError");
const axios = require("axios");
const exchange = require("../util/exchange");
const { ExternalService } = require("../services");
const mailgun = require("mailgun-js")({
apiKey: process.env.MAILGUN_API_KEY,
domain: process.env.MAILGUN_DOMAIN,
});
const detail = (req, res, next) => {
const isCTAdmin = req.user.position >= Position.CT;
let subscriptionQuery;
if (isCTAdmin) {
subscriptionQuery = Subscription.findOne({
_id: req.params.subscriptionId,
});
} else {
subscriptionQuery = Subscription.findOne({
_id: req.params.subscriptionId,
company: req.user.company.id,
});
}
subscriptionQuery
.populate("plan service provider client addons.plan addons.options company")
.exec()
.then((subscription) => {
if (!subscription)
return Promise.reject(ApiError.NotFound("Subscription not found"));
return Promise.all([subscription, subscription.availableAddons()]);
})
.then(async ([subscription, availableAddons]) => {
let subscriptionObject = subscription.toObject();
subscriptionObject.addons = subscriptionObject.addons.filter(
(a) => a.status === SubscriptionStatus.ACTIVE
);
// Populate available addons
subscriptionObject.availableAddons = availableAddons
.map((a) => a.toObject())
.filter((a) =>
subscription.client.authorized_segments.includes(a.segment)
);
// Get dynamic prices for addons
subscriptionObject.addons.forEach((a, index) => {
const plan = subscription.addons[index].plan;
a.plan.price = isCTAdmin
? plan.cost
: plan.price(req.user.company.rates, plan.currency);
});
// Set dynamic price
subscriptionObject.availableAddons.forEach((p, index) => {
const plan = availableAddons[index];
p.price = isCTAdmin
? plan.cost
: plan.price(req.user.company.rates, plan.currency);
});
// Set price for subscription itself
const plan = subscription.plan;
subscriptionObject.plan.price = isCTAdmin
? plan.cost
: plan.price(req.user.company.rates, plan.currency);
delete subscriptionObject.plan.cost;
// Set Status
if (subscriptionObject.provider.type === "kaspersky") {
if (subscriptionObject.service.package_type === "Suscripcion") {
const response = await getToken({
type: "get",
url: `${process.env.API_PUBLICA}/suscripciones/kaspersky/${subscriptionObject.identifier}`,
});
let dataObject = {
ActivationCode: response.data.ActivationCode,
status: response.data.Status,
};
subscriptionObject.statusSubscription = dataObject;
return subscriptionObject;
} else {
const response = await getToken({
type: "get",
url: `${process.env.API_PUBLICA}/suscripciones/kaspersky/async/status/${subscriptionObject.identifier}`,
});
let dataObject = {
descripcion: response.data.GetOrderStatusResult.Data.Description,
status: response.data.GetOrderStatusResult.Data.ProcessingStatus,
};
subscriptionObject.statusSubscription = dataObject;
return subscriptionObject;
}
}
// if (subscriptionObject.provider.type === 'bind') subscriptionObject.plan.price = subscriptionObject.metadata.suscriptionData.Quote / 1.16
// subscriptionObject.company = subscription.company.info;
// return subscriptionObject
})
.then((subscription) => res.json(subscription))
.catch(next);
};
plan.js
const mongoose = require("mongoose");
const moment = require("moment");
const ObjectId = mongoose.Schema.ObjectId;
const {
PlanSegment,
PLAN_SEGMENTS,
CURRENCIES,
SubscriptionStatus,
VENDOR_ACCOUNT_TYPES,
PERIODS,
Period,
} = require("../constants/enums");
const Big = require("big.js");
const commonModelOptions = require("../util/commonModelOptions");
const SubscriptionChange = require("./subscriptionChange");
const PlanSchema = new mongoose.Schema(
{
name: { type: String, required: true },
description: { type: String, required: true },
service: { type: ObjectId, ref: "Service" },
identifier: { type: String, index: true }, // External ID by provider
cost: Number,
prices_by_quantity: {
type: [
{
min_q: Number,
max_q: Number,
price: Number,
band: String,
ct_price: Number,
ct_key: String,
},
],
default: [],
},
currency: { type: String, enum: CURRENCIES, required: true },
unit: String,
accountType: { type: String, enum: VENDOR_ACCOUNT_TYPES, required: true },
period: { type: String, enum: PERIODS, default: Period.month },
is_addon: { type: Boolean, default: false },
depends_on: { type: [{ type: ObjectId, ref: "Plan" }], default: [] },
options: { type: mongoose.Schema.ObjectId, ref: "Options" },
segment: {
type: String,
enum: PLAN_SEGMENTS,
default: PlanSegment.PRIVATE,
},
ct_key: { type: String, default: "CARGO100" },
inmutable: { type: Boolean, default: false },
is_incomplete: { type: Boolean, default: false },
subscription_limit_min: { type: String, defaul: null },
subscription_limit_max: { type: String, defaul: null },
type: { type: String, default: null },
},
commonModelOptions
);
And I get this message:
// 20230116112216
// http://localhost:4040/api/subscriptions/5f108e96e55425340a7a7c6b
{
"message": "Cast to ObjectId failed for value \"" (type Object) at path \"depends_on\" for model \"Plan\"",
"ok": false
}
How can I solve this?

Mongoose find by a subdocument's value

I have 2 schemas
const schema = Schema({
headLine: {
type: String,
required: false
},
availableDays: [{
type: Schema.Types.ObjectId,
ref: AvailableDay
}]
}, {collection: 'providers', timestamps: true});
module.exports = mongoose.model("Provider", schema);
const schema = Schema({
day: {
type: String,
enum: ['Mondays','Tuesdays','Wednesdays','Thursdays','Fridays','Saturdays','Sundays']
},
timeFrom: String,
timeTo: String
}, {collection: 'availableDays', timestamps: true});
module.exports = mongoose.model("AvailableDay", schema);
Then in a route I call to a repository like this
router.get('/', async (req, res) => {
const match = {};
const sort = {};
const options = {};
// Arrange sort
if(req.query.sortBy){
const sortArray = JSON.parse(req.query.sortBy);
sortArray.map(e => sort[e[0]] = e[1] && e[1] === 'desc' ? -1 : 1);
options['sort'] = sort
}
// Get the pagination: limit how many, skip where it starts
if(req.query.limit) {
options['limit'] = parseInt(req.query.limit);
}
if(req.query.skip) {
options['skip'] = parseInt(req.query.skip);
}
const docs = await ProviderRepository.findBy(match, {}, options);
res.status(200).json(docs)
});
So what I need here is to filter providers for an AvailableDay monday and return the docs and count the total docs for pagination. I'm doing something like this without success
const findBy = async (params, projection = "", options = {}, callback) => {
const data = () => {
Provider.find(params, projection, options)
.populate([{path: 'user', match: {gender: 'F'}}]).exec((error, e) => {
if (error) {
console.log('error:', error)
return {error: error}; // returns error in json
}
return e.filter(i => i.user);
});
};
const total = await Provider.countDocuments(params).exec();
return {data(), total}
}
Thanks in advance
Use mongoose-aggregate-paginate-v2 and update your schema. If you use that package then you have to convert your queries from populate to aggregate style.
STEP 1: Update schema. Sample Schema:
const mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-aggregate-paginate-v2');
const Schema = mongoose.Schema;
let definition = {
headLine: {
type: String,
required: false
},
availableDays: [{
type: Schema.Types.ObjectId,
ref: AvailableDay
}]
};
let options = {
collection: 'providers'
};
let providerSchema = new Schema(definition, options);
providerSchema.plugin(mongoosePaginate);
module.exports = mongoose.model('providers', providerSchema);
STEP 2: Update controller. Sample code in controller:
router.get('/', async (req, res) => {
const match = {}
const sort = {
// Fill it based on your sort logic.
}
const paginateOptions = {
page: req.query.page, // Page number like: 1, 2, 3...
limit: req.query.limit // Limit like: 10, 15, 20...
};
ProviderRepository
.findBy(match, {}, sort, paginateOptions)
.then(() => {
res.status(200).json(docs)
})
.catch(() => {
res.status(HTTP_ERROR_CODE).json({ "error": "Your error message" })
})
});
STEP 3: Update manager. Sample code in manager:
const findBy = (match, projection, sort, paginateOptions) => {
if (!paginateOptions) {
paginateOptions = {
pagination: false
};
}
let providerAggregate = providerSchema.aggregate([
{
$lookup: {
from: "availableDays",
let: { days: "$availableDays" },
pipeline: [
{
$match: {
$expr: {
$in: ["$$availableDays", "$day"]
}
}
}
],
as: "availableDays"
}
},
{
$lookup: {
from: "users", // I dont know the collection name
let: { user_id: "$user" }
pipeline: [
{
$match: {
"gender": 'F',
$expr: {
$eq: ["$_id", "$$user_id"]
}
}
}
],
as: "users"
}
}
{ $sort: sort }
]);
return providerSchema
.aggregatePaginate(providerAggregate, paginateOptions)
.then(res => {
return res;
})
.catch(err => {
throw err;
});
};

Mongoose: How to update an existing element in array?

I was wondering if there is a better way to update an existing element in an array instead of fetching database three times. If you have any ideas I would appreciate it. Thank you!
const creatStock = async (symbol, webApiData) => {
try {
// reversed array
const webApiDataReversed = webApiData.reverse();
const query = { symbol };
const update = { $addToSet: { data: webApiDataReversed } };
const options = { upsert: true, new: true };
// create/update Stock
const stockResult = await Stock.findOneAndUpdate(query, update, options);
const lastElement = stockResult.data.length - 1;
const updatePull = {
$pull: { data: { date: stockResult.data[lastElement].date } },
};
// removes last date from data array
await Stock.findOneAndUpdate(query, updatePull);
// update Stock
await Stock.findOneAndUpdate(query, update);
} catch (ex) {
console.log(`creatStock error: ${ex}`.red);
}
};
Schema
const ChildSchemaData = new mongoose.Schema({
_id: false,
date: { type: mongoose.Types.Decimal128 },
open: { type: mongoose.Types.Decimal128 },
high: { type: mongoose.Types.Decimal128 },
low: { type: mongoose.Types.Decimal128 },
close: { type: mongoose.Types.Decimal128 },
volume: { type: mongoose.Types.Decimal128 },
});
const ParentSchemaSymbol = new mongoose.Schema({
symbol: {
type: String,
unique: true,
},
// Array of subdocuments
data: [ChildSchemaData],
});
module.exports.Stock = mongoose.model('Stock', ParentSchemaSymbol);
Output
Well, if you don't need to return the updated document, Please try this one - this will just return a write result, with this things can be achieved in one DB call :
const creatStock = async (symbol, webApiData) => {
try {
// reversed array
const webApiDataReversed = webApiData.reverse();
const query = { symbol };
await Stock.bulkWrite([
{
updateOne:
{
"filter": query,
"update": { $pop: { data: 1 } }
}
}, {
updateOne:
{
"filter": query,
"update": {
$addToSet: {
data: webApiDataReversed
}
}
}
}
])
} catch (ex) {
console.log(`creatStock error: ${ex}`.red);
}
};
Ref : mongoDB bulkWrite
you can do like this way :
const creatStock = async (symbol, webApiData) => {
try {
// reversed array
const webApiDataReversed = webApiData.reverse();
const query = { symbol };
let stock = await Stock.findOne(query);
if(stock){
let stockData = JSON.parse(JSON.stringify(stock.data));
if(stockData.length>0){
stockData.pop();
}
stockData.concat(webApiDataReversed);
stock.data = stockData;
await stock.save();
}
} catch (ex) {
console.log(`creatStock error: ${ex}`.red);
}

Why is this mongoose 'findOne' query always returning null?

I am trying to find a specific document with mongoose in my Cosmosdb with this query described below.
const mongoose = require('mongoose');
var ObjectID = require('mongodb').ObjectID
const keys = require('../config/keys');
const Item = mongoose.model('items');
const uploadToBlob = async (containerName, blobName, json, id) => {
console.log('id', id)
Item.findOne({ _id: id }, (foundItem) => {
console.log(foundItem)
});
console.log('here')
Item.findOneAndDelete({ name: blobName });
};
I am successfully able to find the document when querying like this below.
const scanMongo = () => {
Item.find({
_id: {
$gt: ObjectID.createFromTime(Date.now() / keys.mongoPurgeInterval)
}}, (err, foundItems) => {
if(err) {
console.log("Oops", err);
return;
}
foundItems.forEach(item => {
JSON.stringify(item)
const blobName = item.name;
json = "'"+item+"'"
const id = item._id
uploadToBlob(keys.containerName, blobName, json, id);
});
});
}
This is what the object I'm looking for looks like when pulled from the query above.
[ { _id: 5cabd5c6e16288230cba2cf6, name: 'test', value: 1, __v: 0 } ]
For kicks, here my model.
const mongoose = require('mongoose');
const { Schema } = mongoose;
const itemSchema = new Schema({
name: String,
value: Number,
});
mongoose.model('items', itemSchema);
I'm befuddled. Any help would be bawler. Thanks!!!
Yeah, the first parameter is supposed to catch the error.
Item.findOne({ _id: id }, (error, foundItem) => {
console.log(foundItem)

Update fields in object with mongoose in mongodb

I have a simple collection in mongodb.
I use mongoose.
I have users model with one field type object.
And I want change this object dynamically. But this code doesn't work, I used findByIdAndUpdate(), findById, findOne(), findOneAndUpdate().
const UsersSchema = mongoose.Schema({
likes: {}
},
{ collection: 'users' });
const Users = mongoose.model('Users', UsersSchema);
const id ="5b4c540f14f353a4b9875af4";
const thems = ['foo', 'bar'];
Users.findById(id, (err, res) => {
thems.map(item => {
if (res.like[item]) {
res.like[item] = res.like[item] + 1;
} else {
res.like[item] = 1;
}
});
res.save();
});
I believe that, for solve this problem you need to add more fields in your schema:
I created one example with this data:
const UsersSchema = new mongoose.Schema({
likes :[
{
thema:{
type: String
},
likes_amount:{
type: Number
},
_id:false
}]
});
module.exports = mongoose.model('Users', UsersSchema);
I added one user:
var newUser = new UserModel({
likes:[{
thema:'foo',
likes_amount:1
}]
});
newUser.save();
Here the code that increment the likes per thema:
const thems = ['foo', 'bar'];
const userId = "5b4d0b1a1ce6ac3153850b6a";
UserModel.findOne({_id:userId})
.then((result) => {
var userThemas = result.likes.map(item => {
return item.thema;
});
for (var i = 0; i < thems.length; i++) {
//if exists it will increment 1 like
if (userThemas.includes(thems[i])) {
UserModel.update({_id: result._id, "likes.thema" : thems[i]}, {$inc: {"likes.$.likes_amount": 1}})
.then((result) => {
console.log(result);
}).catch((err) => {
console.log(err)
});
} else {
//if doesn't exist it will create a thema with 1 like
UserModel.update({_id: result._id},
{
$addToSet: {
likes: {
$each: [{thema: thems[i], likes_amount: 1}]
}
}})
.then((result) => {
console.log(result);
}).catch((err) => {
console.log(err)
});
}
}
}).catch((err) => {
console.log(err)
});
Database result of this increment:
I hope that it can help you.

Categories

Resources