How to remove multiple records in nodejs using mongoose - node.js

Tried to remove multiple records in single call from mongodb using mongoose but not working.Where i want to change in my code.Please help to find solution.
In my code if i use like this.. it is working..
({ p_id: { $in: ['Cs1', 'Cs2', 'Cs3']} }
but if use below like
({ p_id: { $in: [records_pids] } } it is not working.Because i am getting this array values by api call.
MongoDB:
{
p_id:"Cs1",
name:"Test",
value:"Power"
},
{
p_id:"Cs2",
name:"Test",
value:"Power"
},
{
p_id:"Cs3",
name:"Test",
value:"Power"
},
{
p_id:"Cs4",
name:"Test",
value:"Power"
},
{
p_id:"Cs5",
name:"Test",
value:"Power"
}
data.controller.js:
module.exports.deleteMultipleRecord = (req, res, next) => {
var collectionMDName = req.query.collectionname;
var records_pids = req.query.pids; //Array value Cs1, Cs2, Cs3
var tableMDModal = mongoose.model(collectionMDName);
tableMDModal.deleteMany({ p_id: { $in: [records_pids] } }, function(err, docs) {
if (err) {
console.log('ss' + err);
return
} else {
console.log("Successful deleted selected records");
res.json({ data: docs, success: true, msg: 'Successful deleted selected records.', cname: collectionMDName });
}
})
}

module.exports.deleteMultipleRecord = (req, res, next) => {
var collectionMDName = req.query.collectionname;
var records_pids = req.query.pids; //Array value CS1, CS2, CS3
var tableMDModal = mongoose.model(collectionMDName);
tableMDModal.deleteMany({ p_id: { $in: records_pids } }, function(err, docs) {
if (err) {
console.log('ss' + err);
return
} else {
console.log("Successful deleted selected records");
res.json({ data: docs, success: true, msg: 'Successful deleted selected records.', cname: collectionMDName });
}
})
}
the error is semantic , rather than searching for values $in: [CS1, CS2, CS3], the search is being made as [[CS1, CS2, CS3]]
Also,have a look at https://mongoosejs.com/docs/models.html for defining models.
MongoDB Enterprise Cluster0-shard-0:PRIMARY> use new
switched to db new
MongoDB Enterprise Cluster0-shard-0:PRIMARY> use neo
switched to db neo
MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.coll.insertMany([{ p_id:"Cs1", name:"Test", value:"Power" }, { p_id:"Cs2", name:"Test", value:"Power" }, { p_id:"Cs3", name:"Test", value:"Power" }, { p_id:"Cs4", name:"Test", value:"Power" }, { p_id:"Cs5", name:"Test", value:"Power" }])
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5ecb90001a40be1d77da2aa8"),
ObjectId("5ecb90001a40be1d77da2aa9"),
ObjectId("5ecb90001a40be1d77da2aaa"),
ObjectId("5ecb90001a40be1d77da2aab"),
ObjectId("5ecb90001a40be1d77da2aac")
]
}
MongoDB Enterprise Cluster0-shard-0:PRIMARY> const records_id =["Cs1","Cs2","Cs3"]
MongoDB Enterprise Cluster0-shard-0:PRIMARY> db.coll.deleteMany({p_id:{$in:records_id}})
{ "acknowledged" : true, "deletedCount" : 3 }

Related

NodeJS Array not filling up

Im using mongodb as a database after getting the valuation data which are more then one , i loop inside them and get the offers according to the offres_id , I asure you that the database has data inside and to querys are working correctly in fact if i console log them in each iteration i get this result
{
offre: [
{
_id: new ObjectId("63320bf87123db5691c51392"),
user_id: '63304e44aa63c519d887dac1',
brand: 'HP',
model: 'AZGGH-89855A',
photo: '16642242480661659650294043-bs-5.png',
scan_method: 'manual',
__v: 0
}
],
valuation: {
_id: new ObjectId("63320d39a5677df3cebcbdae"),
user_id: '63304e44aa63c519d887dac1',
offre_id: '63320bf87123db5691c51392',
given_price: '1236',
comment: 'no comment',
__v: 0
}
}
{
offre: [
{
_id: new ObjectId("6334202a8c7e6d90b35ee999"),
user_id: '63304e44aa63c519d887dac1',
brand: 'DELL',
model: 'AZGGH-89855A',
photo: '1664360490280Capture.PNG',
scan_method: 'manual',
__v: 0
}
],
valuation: {
_id: new ObjectId("633420be8c7e6d90b35ee99e"),
user_id: '63304e44aa63c519d887dac1',
offre_id: '6334202a8c7e6d90b35ee999',
__v: 0
}
}
but when i try storing each offre & valuation at the same array cell and return it i get this as a result
[]
However this is the code
router.get('/get', async (req, res) => {
try {
Valuation.find({ user_id: req.session.userID })
.exec()
.then(valuation => {
let myData = [];
if (valuation) {
for (let i = 0; i < valuation.length; i++) {
Offre.find({_id : valuation[i].offre_id})
.exec()
.then(offre=>{
myData.push({offre : offre, valuation : valuation[i]})
})
}
res.status(200).json(myData)
} else {
res.status(404).json('no valuations found')
}
})
.catch(error => {
res.status(500).json(error.message)
})
} catch (error) {
res.status(500).json({ error: error.message })
}
})
Since you're already using async, it would be a shame to not use await to simplify your code:
router.get("/get", async (req, res) => {
try {
const valuation = await Valuation.find({ user_id: req.session.userID }).exec();
if (valuation) {
let myData = [];
for (let i = 0; i < valuation.length; i++) {
const offre = await Offre.find({ _id: valuation[i].offre_id }).exec();
myData.push({ offre: offre, valuation: valuation[i] });
}
res.status(200).json(myData);
} else {
res.status(404).json("no valuations found");
}
} catch (error) {
res.status(500).json({ error: error.message });
}
});
You can probably also speed up the Offre query by using an $in query to retrieve all offres with one query, but that's another thing.

Automate NodeJS Express Get and Post request using Cron

I have an existing get and post request from database which is:
router.post('/stackExample', async (req, res) => {
try {
//MAKE GET REQUEST FROM MONGODB
const stackCron = await Borrower.aggregate([
{ $unwind: { path: "$application", preserveNullAndEmptyArrays: true } },
{
$project: {
'branch': '$branch',
'status': '$application.status',
},
},
{ $match: { status: 'Active' } },
]);
//MAKE POST REQUEST TO MONGODB
for (let k = 0; k < stackCron.length; k++) {
const branch = stackCron[k].branch;
const status = stackCron[k].status;
const lrInterest = await Financial.updateOne({ accountName: 'Processing Fee Income'},
{
$push:
{
"transactions":
{
type: 'Credit',
firstName: 'SysGen',
lastName: 'SysGen2',
amount: 100,
date: new Date(),
}
}
})
}
res.json({ success: true, message: "Success" });
} catch (err) { res.json({ success: false, message: 'An error occured' }); }
});
This code works fine if request is made using the client but I want to automate this via cron:
Here is what I did:
var CronJob = require('cron').CronJob;
var job = new CronJob('* * * * * *', function () {
makeRequest()
}, null, true, 'America/Los_Angeles');
job.start();
function makeRequest(message){
//Copy-paste entire router post request.
}
There seems to be no response if I copy-paste my code in the function. What have I missed?
There is no response from a cron job because there is no request coming to your makeRequest function. That makes sense because a cron job is independent of any incoming requests.
One other reason, you might not be getting any data from your updateOne operation is that it doesn't return the updated document. It returns the status of that operation instead. Take a look here. If you want to get the updated document you might want to use findOneAndUpdate.
const response = await Todo.findOneAndUpdate(
{ _id: "a1s2d3f4f4d3s2a1s2d3f4" },
{ title: "Get Groceries" },
{ new: true }
);
// response will have updated document
// We won't need this here. This is just to tell you how to get the updated document without making another database query explicitly
The body of your router function is performing an async/await operation. But you didn't specify the makeRequest function to be async. This could also be the issue.
cron job will update the database but if you want to get the updated documents, you'll have to make a GET call to the server and define a new route, with required parameters/query.
Your makeRequest function will look something like this
async function makeRequest() {
try {
//MAKE GET REQUEST FROM MONGODB
const stackCron = await Borrower.aggregate([
{ $unwind: { path: "$application", preserveNullAndEmptyArrays: true } },
{
$project: {
branch: "$branch",
status: "$application.status",
},
},
{ $match: { status: "Active" } },
]);
//MAKE POST REQUEST TO MONGODB
for (let k = 0; k < stackCron.length; k++) {
const branch = stackCron[k].branch;
const status = stackCron[k].status;
const lrInterest = await Financial.updateOne(
{ accountName: "Processing Fee Income" },
{
$push: {
transactions: {
type: "Credit",
firstName: "SysGen",
lastName: "SysGen2",
amount: 100,
date: new Date(),
},
},
}
);
}
/**
* Write to a log file if you want to keep the record of this operation
*/
} catch (err) {
/**
* Similarly write the error to the same log file as well.
*/
}
}
In your cron job
var job = new CronJob(
"* * * * * *",
async function () {
await makeRequest();
},
null,
true,
"America/Los_Angeles"
);
Your new route
router.get("/stack/:accountName", async (req, res, next) => {
const { accountName } = req.params;
try {
const financial = await Financial.find({ accountName });
res.status(200).json({ message: "success", data: financial });
} catch (err) {
res.status(500).json({ message: "error", reason: err.message });
}
});
Simply call it as
fetch(
`http://example.net/stack/${encodeURIComponent("Processing Fee Income")}`,
{ method: "GET" }
);

API Only sends 1 chunk of metadata when called

I have a problem with my API that sends metadata when called from my smart contract of website. Its NFT tokens and my database is postgres and API is node.js
The problem is when I mint 1 NFT metadata works perfect, but if I mint 2 or more it will only ever send 1 chunk of data? So only 1 NFT will mint properly and the rest with no data?
Do I need to set a loop function or delay? Does anyone have any experience with this?
Any help would be much appreciated.
Below is the code from the "controller" folder labeled "nft.js"
const models = require("../../models/index");
const path = require("path");
const fs = require("fs");
module.exports = {
create_nft: async (req, res, next) => {
try {
const dir = path.resolve(__dirname + `../../../data/traitsfinal.json`);
const readCards = fs.readFileSync(dir, "utf8");
const parsed = JSON.parse(readCards);
console.log("ya data ha final ??", parsed);
parsed.forEach(async (item) => {
// return res.json(item)
let newNft = await models.NFT.create({
name: item.Name,
description: item.Description,
background: item.Background,
body: item.Body,
mouth: item.Mouth,
eyes: item.Eyes,
head_gear: item.Head_Gear,
tokenId: item.tokenId,
image: item.imagesIPFS,
});
});
return res.json({
data: "nft created",
error: null,
success: true,
});
} catch (error) {
console.log("server error", error.message);
next(error);
}
},
get_nft: async (req, res, next) => {
try {
const { id } = req.params;
// console.log("id ?????????",id)
// console.log("type of ",typeof(id))
// const n=Number(id)
// console.log("type of ",typeof(id))
const nft = await models.NFT.findByPk(id);
if (!nft) {
throw new Error("Token ID invalid");
}
if (!nft.isMinted) {
throw new Error("Token not minted");
}
console.log(nft);
// }
const resObj = {
name: nft.name,
description: nft.description,
image: `https://gateway.pinata.cloud/ipfs/${nft.image}`,
attributes: [
{ trait_type: "background", value: `${nft.background}` },
{ trait_type: "body", value: `${nft.body}` },
{ trait_type: "mouth", value: `${nft.mouth}` },
{ trait_type: "eyes", value: `${nft.eyes}` },
{ trait_type: "tokenId", value: `${nft.tokenId}` },
{
display_type: "number",
trait_type: "Serial No.",
value: id,
max_value: 1000,
},
],
};
return res.json(resObj);
} catch (error) {
console.log("server error", error.message);
next(error);
}
},
get_nft_all: async (req, res, next) => {
try {
// console.log("id ?????????",id)
// console.log("type of ",typeof(id))
// const n=Number(id)
// console.log("type of ",typeof(id))
const nft = await models.NFT.findAndCountAll({
limit: 10
});
// console.log(nft);
if (!nft) {
throw new Error("Token ID invalid");
}
// if (nft.isMinted) {
// throw new Error("Token not minted");
// }
// console.log(nft);
// }
var resObjarr = [];
for (var i = 0; i < nft.rows.length; i++) {
resObj = {
name: nft.rows[i].name,
description: nft.rows[i].description,
image: `https://gateway.pinata.cloud/ipfs/${nft.rows[i].image}`,
attributes: [
{ trait_type: "background", value: `${nft.rows[i].background}` },
{ trait_type: "body", value: `${nft.rows[i].body}` },
{ trait_type: "mouth", value: `${nft.rows[i].mouth}` },
{ trait_type: "eyes", value: `${nft.rows[i].eyes}` },
{ trait_type: "tokenId", value: `${nft.rows[i].tokenId}` },
{
display_type: "number",
trait_type: "Serial No.",
value: nft.rows[i].id,
max_value: 1000,
},
],
};
resObjarr.push(resObj);
}
console.log(JSON.stringify(resObjarr))
return res.json(resObjarr);
} catch (error) {
console.log("server error", error.message);
next(error);
}
},
mint: async (req, res, next) => {
try {
const { id } = req.params;
const updated = await models.NFT.findByPk(id);
if (!updated) {
throw new Error("NFT ID invalid");
}
if (updated.isMinted) {
throw new Error("NFT Already minted");
}
updated.isMinted = true;
updated.save();
return res.json({
data: "Token minted successfully",
error: null,
success: true,
});
} catch (error) {
console.log("server error", error.message);
next(error);
}
},
};
Below is from the routes folder.
const router = require("express").Router();
const auth=require("../middleware/auth")
const {
create_nft,
get_nft,
get_nft_all,
mint
} = require("../controller/nft");
router.post(
"/create",
create_nft
);
router.get(
"/metadata/:id",
get_nft
);
router.get(
"/metadata",
get_nft_all
);
router.put(
"/mint/:id",
mint
);
module.exports = router;
Looking your code,you may having some kind of asyncrhonous issue in this part:
parsed.forEach(async (item) => {
// return res.json(item)
let newNft = await models.NFT.create({
name: item.Name,
description: item.Description,
background: item.Background,
body: item.Body,
mouth: item.Mouth,
eyes: item.Eyes,
head_gear: item.Head_Gear,
tokenId: item.tokenId,
image: item.imagesIPFS,
});
});
Because .forEach is a function to be used in synchronous context and NFT.create returns a promise (that is async). So things happens out of order.
So one approach is to process the data first and then perform a batch operation using Promise.all.
const data = parsed.map(item => {
return models.NFT.create({
name: item.Name,
description: item.Description,
background: item.Background,
body: item.Body,
mouth: item.Mouth,
eyes: item.Eyes,
head_gear: item.Head_Gear,
tokenId: item.tokenId,
image: item.imagesIPFS,
})
})
const results = await Promise.all(data)
The main difference here is Promise.all resolves the N promises NFT.create in an async context in paralell. But if you are careful about the number of concurrent metadata that data may be too big to process in parallel, then you can use an async iteration provided by bluebird's Promise.map library.
const Promise = require('bluebird')
const data = await Promise.map(parsed, item => {
return models.NFT.create({
name: item.Name,
description: item.Description,
background: item.Background,
body: item.Body,
mouth: item.Mouth,
eyes: item.Eyes,
head_gear: item.Head_Gear,
tokenId: item.tokenId,
image: item.imagesIPFS,
})
})
return data

How to update existing MongoDB document with Nested JSON using Angular?

I am trying to store JSON array to the existing document with the id who logged in. I don't have an idea how to post this array to backend.
cake.component.ts
export class CakeComponent implements OnInit {
form: FormGroup;
constructor(
public fb: FormBuilder,
private api: ApiService
) { }
ngOnInit() {
this.submitForm();
}
submitForm() {
this.form = this.fb.group({
url: ['', [Validators.required]],
width : ['', [Validators.required]],
height: ['', [Validators.required]]
})
}
submitForm() {
if (this.form.valid) {
this.api.AddCake(this.form.value).subscribe();
}
}
}
Existing MongoDB document Cakes
{
"id": "0001",
"type": "donut",
"name": "Cake"
}
Expected Output
{
"id": "0001",
"type": "donut",
"name": "Cake",
"image": {
"url": "images/0001.jpg",
"width": 200,
"height": 200
}
}
Here is the basic code, please update it accordingly :
/** You can split this code into multiple files, schema into a file &
mongoDB connectivity into a common file & actual DB update can be placed where ever you want */
const mongoose = require('mongoose')
const Schema = mongoose.Schema;
const cakeSchema = new Schema({
id: String,
type: String,
name: String,
image: {
url: String,
width: Number,
height: Number
}
});
const cakeModel = mongoose.model('Cakes', cakeSchema, 'Cakes');
let form = {
"url": "images/0001.jpg",
"width": 200,
"height": 200
}
async function myDbConnection() {
const url = 'yourDBConnectionString';
try {
await mongoose.connect(url, { useNewUrlParser: true });
console.log('Connected Successfully')
let db = mongoose.connection;
// You can use .update() or .updateOne() or .findOneAndUpdate()
let resp = await cakeModel.findOneAndUpdate({ id: '0001' }, { image: form }, { new: true });
console.log('successfully updated ::', resp)
db.close();
} catch (error) {
console.log('Error in DB Op ::', error);
db.close();
}
}
module.exports = myDbConnection();
Update :
In case if you're using mongoDB driver but not mongoose :
const MongoClient = require('mongodb').MongoClient;
// Connection URL
const url = 'yourDBConnectionString';
// Database Name
const dbName = 'test';
// Create a new MongoClient
const client = new MongoClient(url);
let form = {
"url": "images/0001.jpg",
"width": 200,
"height": 200
}
// Use connect method to connect to the Server
client.connect(async function (err) {
if (err) console.log('DB connection error ::', err)
console.log("Connected successfully to server");
try {
// You can use .update() or .updateOne() or .findOneAndUpdate()
let resp = await client.db(dbName).collection('Cakes').findOneAndUpdate({ id: '0001' }, { $set: { image: form } }, { returnOriginal: false });
console.log('successfully updated ::', resp , 'resp value ::', resp.value)
client.close();
} catch (error) {
console.log('Error in DB Op ::', error);
client.close();
}
});

How to update subdocument value through mongoose?

I am trying to update the value of a nested document through a PUT request. It is working for values in the document, but not in the subdocument.
const AnotherSchema = new Schema ({
Name: String,
Age: Number,
Appearance: {
Hair: String, Eyes: String, Height: Number};
My route looks like this
router.put("/looks/:id/edit", function(req, res) {
var Name= "blob";
var Hair= "blue";
AnotherSchema.findByIdAndUpdate(req.params.id, {Name, Hair}, function(err, feedback){
if (err){
res.send("error");
} else {
res.redirect("/looks");
}
});
});
This route works for updating Name, but not Hair. I have tried Appearance.Hair, but this throws an error in the console for an unexpected . I have also tried [], () and {} but none of these do the trick, nor do " " and this issue does not seem to appear in the docs.
You should be providing the paths via the object notation to the props you want to update:
router.put("/looks/:id/edit", function(req, res) {
AnotherSchema.findByIdAndUpdate(req.params.id, {
Name: "blob",
Appearance: {
Hair: "blue"
}
}, function(err, feedback) {
if (err) {
res.send("error");
} else {
res.redirect("/looks");
}
});
});
The above findByIdAndUpdate is equivalent to:
{ $set: { Name: "blob", Appearance: { Hair: "blue" } } } as per the docs
You should use the $set operator, otherwise you will replace the whole record with the object provided as argument.
var updateObj = {
{ $set: { Name: "blob", Appearance: { Hair: "blue" } } }
};
AnotherSchema.findByIdAndUpdate(req.params.id, updateObj, function (err, feedback) { ... });

Resources