I have a table with three fields.
--------------------------------
id_ram | value | um
id_ram is primary key.
I'm designing an Express API with sequelize. I am not able to update multiple rows of this table.
I am passing json array like below.
[
{"id_ram":"54","value":"11","um":"GB"},
{"id_ram":"34","value":"22","um":"GB"},
{"id_ram":"70","value":"33","um":"GB"}
]
This is what I have tried so far.
router.post('/update',function (req, res) {
var api_name = middleware_name + " /update";
// - Check if the input array is passed
if(req.body.array == undefined) {
var jsonErrorResponse = api_manager.PrepareJSONResponse(api_name, "", "value of input parameter [array] is undefined");
api_manager.WriteErrorLogFile(req,api_name,jsonErrorResponse,jsonErrorResponse);
res.send(jsonErrorResponse);
return;
}
else {
var create_values_array = "";
try {
//Parse INPUT JSON Array
create_values_array = JSON.parse(req.body.array);
}
catch (err) {
//Raise SyntaxError
var jsonErrorResponse = api_manager.PrepareJSONResponse(api_name,"",err.message);
var jsonInternalError = api_manager.PrepareJSONResponse(api_name,"",err);
api_manager.WriteErrorLogFile(req,api_name,jsonErrorResponse,jsonInternalError);
//Send error Response
res.send(jsonErrorResponse);
}
ObjectModel.bulkCreate(
create_values_array
, {updateOnDuplicate: ["id_ram"]})
.then(created_objects => { // Notice: There are no arguments here, as of right now you'll have to...
//Send Response and Log Action
var jsonData = api_manager.PrepareJSONResponse(api_name,created_objects,"");
api_manager.WriteInfoLogFile(req,api_name,jsonData);
res.send(jsonData);
}).catch (function (err) {
//Write Error Log
var jsonErrorResponse = api_manager.PrepareJSONResponse(api_name,"",err.message);
var jsonInternalError = api_manager.PrepareJSONResponse(api_name,"",err);
api_manager.WriteErrorLogFile(req,api_name,jsonErrorResponse,jsonInternalError);
//Send error Response
res.send(jsonErrorResponse);
});
}
});
How can we implement bulkUpdate like bulkCreate in sequelize orm for MSSQL ?
For bulk create you do it this way.
//array of object to be inserted
const data = [
{field1: "value1"}, {field2: "value2"}...
]
Model.bulkCreate(data, {returning: true}) //if you don't pass returning true it will not return the data
bulkCreate() can also be used for updating as well.
bulkCreate(data , {updateOnDuplicate : true })
Hello {updateOnDuplicate : true } raise an error because SQL Server doesn't support this feature.
Is It possible to take another way ?
You could achieve this by writing a function that calls the Sequelize upsert function in a loop like so:
const records = [
{ field1: 'value1', field2: 'value2' },
...
];
async function bulkUpsert(records) {
return Promise.all(
records.map((record) {
return Model.upsert(record);
})
);
}
Related
I'm using postman to insert or update a giving array with nodejs into SQL Server database table. I'm trying to insert 'user or benutzer' if the id not exist and to update if id exist.
That's how I create my database table:
create Table benutzer (
id int primary key not null,
firstName nvarchar(200) not null,
lastname nvarchar(200) not null,
active bit not null
)
Here is my stored Procedure in SQL Server:
USE benutzerDb;
GO
CREATE TYPE BenutzerList AS TABLE (
[b_id] INT,
b_firstName NVARCHAR(200),
b_lastName NVARCHAR(200),
b_active bit
);
GO
CREATE PROC updateBenutzer (#benutzerList BenutzerList READONLY)
AS
BEGIN
MERGE benutzer AS ben
USING #benutzerList AS blist
ON ben.id = blist.[b_id]
WHEN MATCHED THEN
UPDATE SET
ben.firstName = blist.b_firstName,
ben.lastName = blist.b_lastName,
ben.active = blist.b_active
WHEN NOT MATCHED THEN
INSERT (id,firstName,lastName,active)
VALUES (blist.b_id, blist.b_firstName, blist.b_lastName, blist.b_active);
select * from #benutzerList
END
GO
->and hier how called in SqlServer and it's work perfekt:
use benutzerDb
go
DECLARE #benutzerList BenutzerList
INSERT INTO #benutzerList VALUES(1,'Max','Müller',1),(15,'Ben','Kane',1)
EXEC updateBenutzer #benutzerList
SELECT * FROM benutzer
-> and hier ist my function:
//function to add or update benutzer:
async function addBenutzer() {
try {
const benutzerTable = new sql.Table();
benutzerTable.columns.add('b_id', sql.Int);
benutzerTable.columns.add('b_firstName', sql.NVarChar(200));
benutzerTable.columns.add('b_lastName', sql.NVarChar(200));
benutzerTable.columns.add('b_active', sql.Bit);
const BenutzerList = req.body;
BenutzerList.forEach(benutzer=> {
benutzerTable.rows.add(
benutzer.b_id,
benutzer.b_firstName,
benutzer.b_lastName,
benutzer.b_active
)
});
let pool = await sql.connect(config);
let addBenutzer = await pool.request()
.input('benutzerList', benutzerTable)
.execute("updateBenutzer");
return addBenutzer.recordsets;
}
catch (error) {
console.log(error);
}
}
router.route('/addBenutzer').post((request, response) => {
let Daten = JSON.stringify(request.body);
benutzerController.addBenutzer(Daten).then(result => {
response.status(201).json(result);
});
})
-> hier is the array what i'm giving in postman:
[
{
"id": 1,
"firstName": "Max",
"lastName": "Müller",
"active": true
},
{
"id": 15,
"firstName": "Ben",
"lastName": "Kane",
"active": true
}
]
It supose to update id 1 and insert id 15 but unfortunatly doesn't work, i will be appreciate for your help.
Here is my solution, the request.body was undefind because request was not defined. i edited my function to look much better and i added req and res parameters to async function:
router.post('/addBenutzer', async(req, res) => {
try {
const benutzerTable = new sql.Table();
benutzerTable.columns.add('id', sql.Int);
benutzerTable.columns.add('firstName', sql.NVarChar(200));
benutzerTable.columns.add('lastName', sql.NVarChar(200));
benutzerTable.columns.add('active', sql.Bit);
const BenutzerList = req.body;
BenutzerList.forEach(benutzer => {
benutzerTable.rows.add(
benutzer.id,
benutzer.firstName,
benutzer.lastName,
benutzer.active
)
});
let pool = await sql.connect(config);
let addBenutzer = await pool.request()
.input('benutzerList', benutzerTable)
.execute("updateBenutzer");
res.send(req.body);
return addBenutzer.recordsets;
}
catch (error) {
console.log(error);
}`enter code here`
});
This is my ObjectIds array -
obj_ids = [
"5ee71cc94be8d0180c1b63db",
"5ee71c884be8d0180c1b63d9",
"5ee71c494be8d0180c1b63d6",
"5ee71bfd4be8d0180c1b63d4"
]
I am using these objectids to serach whether they exist in the db or not and based on that I want to send the response to server.
This is the code I am trying but I dont know how to populate the array and send it to the server.
var msg = [];
obj_ids.map((ele) => {
Lead.find({ _id: ele._id }, async function (error, docs) {
if (docs.length) {
msg.push(
`Lead already exist for Lead id - ${ele._id} assgined to ${docs[0].salesPerson}`
);
} else {
msg.push(`Lead doesn't exist for Lead id: ${ele._id}`);
const newDuty = new AssignedDuty({
duty: ele._id,
salesPerson: req.body.salesPerson,
});
await newDuty.save();
}
});
});
res.json(msg);
By doing this approach I am getting an empty array. I cannot put res.json(msg) inside the loop. If it is possible by using async-await, please guide me through.
You don't need to make multiple queries to find whether given object ids exist in the database.
Using $in operator, you can make one query that will return all the documents where the _id is equal to one of the object id in the list.
const docs = await Lead.find({
_id: {
$in: [
"5ee71cc94be8d0180c1b63db",
"5ee71c884be8d0180c1b63d9",
"5ee71c494be8d0180c1b63d6",
"5ee71bfd4be8d0180c1b63d4"
]
}
});
After this query, you can check which object id is present in the docs array and which is absent.
For details on $in operator, see $in comparison operator
Your code can be simplified as shown below:
const obj_ids = [
"5ee71cc94be8d0180c1b63db",
"5ee71c884be8d0180c1b63d9",
"5ee71c494be8d0180c1b63d6",
"5ee71bfd4be8d0180c1b63d4"
];
const docs = await Lead.find({
_id: { $in: obj_ids }
});
const msg = [];
obj_ids.forEach(async (id) => {
const doc = docs.find(d => d._id == id);
if (doc) {
msg.push(
`Lead already exist for Lead id - ${doc._id} assgined to ${doc.salesPerson}`
);
}
else {
msg.push(`Lead doesn't exist for Lead id: ${id}`);
const newDuty = new AssignedDuty({
duty: id,
salesPerson: req.body.salesPerson
});
await newDuty.save();
}
});
res.json(msg);
I have a doc in my collection in this format
name: xyz,
email: xyz#email.com,
age: 30,
address: {
street_no: {
complete_address: somedata,
pincode: somepin
},
city:somecity,
state:somestate,
landmark:nearby
}
And inside this doc I am trying to insert and merge the complete_address with the previous record. To achieve that I am trying this
const database = firebase.firestore();
var dataRef = database.collection('collection');
var query = dataRef.doc(key+"").get().then(doc=>{
if(!doc.exists){
res.send("doesn't exist");
}else{
//few checks
if(doc.data().accessid != accessid){
res.send("accessid doesn't match")
}
//here I am trying to insert and merge with the previous data
var form_path = 'address.street_no.complete_address';
dataRef.doc(key+"."+form_path).set({
another_address
}, {merge: true});
}
}).catch(err=>{
console.log(err)
})
But when I execute this it just add another document in a collection followed by this path key.address.street_no.complete_address.
What can I do to only insert and merge with the previous complete_address ?
There is . instead of / in form_path because got few ideas from this link
I believe your issue lies within the next couple of lines starting at
var form_path = 'address.street_no.complete_address';
Next, You're using dataRef.doc(key+"."+form_path)
which means the only document being set is
/addressCollection/key.{addressCollectionId}
and addressCollectionId being address.street_no.complete_address
Instead what you want to do is access the property within the document using dot notation like so.
address: {
street_no: {
complete_address
Example.
someDocument.update({
"address.street_no.complete_address": "some_data"
});
Note that "some_data" will replace what ever data is currently stored. You'll want to do one read and merge the data. For example.
const anotherAddress = { address: "123 Fake Street" };
const document = firebase
.firestore()
.collection("addressCollection")
.doc("someAddressId");
document
.get()
.then(snap => {
const data = snap.data();
const completeAddress = data.address.street_no.complete_address };
// We're using the spread operator here to combine the current completeAddress with anotherAddress
return { completeAddress, ...anotherAddress };
})
.then(newCompleteAddress =>
document.update({
"address.street_no.complete_address": newCompleteAddress
})
);
I got this working.
So I figured out what I was trying to do earlier will create another document in a collection with data respect to it. So I start treated everything as an object and passed an object data to set() method.
const database = firebase.firestore();
var dataRef = database.collection('collection');
var query = dataRef.doc(key+"").get().then(doc=>{
if(!doc.exists){
res.send("doesn't exist");
}else{
//few checks
if(doc.data().accessid != accessid){
res.send("accessid doesn't match")
}
//here I am trying to insert and merge with the previous data
var mergeData = {
address : {
}
}
var new_address = {
key: "address_data"
}
mergeData.address[street_no] = {complete_address : address}
if(dataRef.doc(key+"").set(mergeData, {merge: true})){
res.send("done")
}else{
res.send("failed")
}
}
}).catch(err=>{
console.log(err)
})
I have a NodeJS server running express with a get method at '/api/jobs/'. When called I get some querystring parameters from the url and they make a query against the MongoDB database to get jobs.
Example Url: '/api/jobs/?Groups=1,2&Statuses=3,4'
The MongoDB query i am trying to construct is this:
{ $or: [{"Group.Id" : 1}, {"Group.Id" : 2}], $or: [{"Status.Id": 3}, {"Status.Id": 4}]}
If I run this directly against the database I get the results I need but I can't think of way of constructing the query dynamically in JavaScript. Any attempt i've made gives me an object like this as the $or property can only exist once in a proper JSON object.
{$or : [{"Group.Id" : 1}, {"Group.Id" : 2}]}
Any ideas on how to do this either using JavaScript or thorugh the MongoDB Node API?
Firstly get the query properties, which will be strings:
const groupString = req.query.Groups; // === '1,2'
const statusString = req.query.Statuses; // === '3,4'
Split at the commas and parse as integers:
const groupNums = groupString.split(',').map(parseInt); // === [1, 2]
const statusNums = statusString.split(',').map(parseInt); // === [3, 4]
Then search for any of the group IDs. Your query should look like this:
const query = {"Group.Id": { $in: groupNums }, "Status.Id": { $in: statusNums } };
Do the same for the status IDs.
You can use this
app.get('/', function(req, res, next) {
var queryArry = [];
for (var i in req.query) {
var sampleObject = { value: [] };
sampleObject.name = i;
req.query[i].split(',').forEach(function(each) {
sampleObject.value.push(parseInt(each));
})
queryArry.push(sampleObject);
}
var mongoquery = {};
for (var i in queryArry) {
mongoquery[queryArry[i].name] = queryArry[i].value;
}
res.send(mongoquery);
});
But in this case, you have to send same name field of MongoDB and query parameter key. If you did this it is fully dynamic query builder.
I'm receiving params from my get request that looks like this:
{ location: 'Venice', weather: 'Dry', what: 'Yoga', who: 'Bob' }
I then query a mongodb database that loops through each of the key and value pairs and queries for their union in the database.
I then save the returned values to outputCaption and then use a callback to pass the outputCaption back.
The problem is the callback gets called as many times as their key-value pairs looped over.
I'm forced to do this because I need the callback inside the db.Phrase.find call but I call that multiple times...
So I've fixed it using the code in app.get (I wait until all the keys have defined values in outputCaption before doing anything)
It works, but I can't imagine it's the best way to do it so I'm hoping there's a less hackish way?
Thanks
server.js
var express = require('express');
var db = require('./modules/db')
var logic = require('./modules/logic')
...
app.get('/phrase', function(req, res){
logic(req.query, function(outputCaption){
var flag = true
for (key in outputCaption){
if (outputCaption[key] === null){
console.log('Incomplete')
var flag = false;
}
}
if (flag === true) {
console.log(outputCaption);
};
});
})
...
logic.js
var db = require('./db')
var logic = function(params, callback){
var outputCaption = {
who: null,
what: null,
location: null,
weather: null
};
for (key in params){
category = key.toLowerCase();
option = params[key].toLowerCase();
db.Phrase.find({$and: [
{category: category},
{option: option}
]}, function(err, phrases){
if (err) return console.error(err);
var options = Object.keys(phrases).length
var idxOfOptionPicked = Math.floor(Math.random() * options)
outputCaption[phrases[idxOfOptionPicked].category] = phrases[idxOfOptionPicked].phrase
callback(outputCaption)
})
}
}
module.exports = logic;
Instead of firing multiple queries and performing a union of the result at the client side, make use of the query operators to allow MongoDB to do the union for you.
That way you:
Avoid multiple hits to the database.
Avoid multiple callback handlers.
Can post process the results in a single callback handler.
You can modify your code to prepare a query object from the request parameter,
var params = {location: 'Venice', weather: 'Dry', what: 'Yoga', who: 'Bob' };
var query = {};
var conditions = [];
Object.keys(params).forEach(function(key){
var $and = {};
$and["category"] = key.toLowerCase();
$and["option"] = params[key];
conditions.push($and);
});
(conditions.length > 1)?(query["$or"] = conditions):(query = conditions[0]);
Now the constructed query looks like:
{ '$or':
[ { category: 'location', option: 'Venice' },
{ category: 'weather', option: 'Dry' },
{ category: 'what', option: 'Yoga' },
{ category: 'who', option: 'Bob' }
]
}
You can pass this object to the find() method, to get the results in a single hit:
db.Phrase.find(query,callback);
This way your code remains cleaner and easier to understand.