I have registered a webhook which constantly generates the data. It has several fields, primary field is id. I am updating this data in a postgres table with update query. The problem is, I have a google sheet and the same data is there. After updating postgres table, I want to update the row in google sheet. How can I use googleSheetsInstance.spreadsheets.values.update() function to update the row with a specific id.
The code I wrote is like this:
let listOfLists = []
jsonArray.forEach(obj => {
const values = Object.values(obj);
listOfLists.push(values);
});
await googleSheetsInstance.spreadsheets.values.update({
auth,
spreadsheetId,
range: "'Sheet1'",
valueInputOption: "USER_ENTERED",
resource: {
majorDimension: "ROWS"
values: listOfLists,
},
});
I believe your goal is as follows.
You want to update rows of the Spreadsheet by searching ticket_id.
The sample value of listOfLists is [[1022, 'ab', 'cd', 'de'], [1023, 'xyz', 'hbw', 'pyg']].
From this sample value, in your situation, the value of ticket_id is column "A".
You want to achieve this using googleapis for Node.js.
You have already been able to get and put values for Google Spreadsheet with Sheets API.
In this case, how about the following sample script?
Sample script:
const googleSheetsInstance = // Please use your client.
const spreadsheetId = "###"; // Please set your Spreadsheet ID.
const sheetName = "Sheet1"; // This is from your script.
const listOfLists = [[1022, "ab", "cd", "de"], [1023, "xyz", "hbw", "pyg"]]; // This sample value is from your comment.
const obj = listOfLists.reduce((o, r) => ((o[r[0]] = r), o), {});
const {data: { values }} = await googleSheetsInstance.spreadsheets.values.get({auth, spreadsheetId, range: sheetName});
await googleSheetsInstance.spreadsheets.values.update({
auth,
spreadsheetId,
range: sheetName,
resource: {values: values.map((r) => obj[r[0]] || r)}, // or values.map((r) => obj[r[0]] || Array(r.length).fill(null)),
valueInputOption: "USER_ENTERED",
});
When this script is run, first, the values are retrieved from the sheet. And, the values of ticket_id of listOfLists are searched from column "A" of the retrieved values. And, the updated values are put on the sheet.
In this sample, 2 API calls are used.
Note:
If the values of ticket_id are not column "A", please modify const obj = listOfLists.reduce((o, r) => ((o[r[0]] = r), o), {}); and resource: {values: values.map((r) => obj[r[0]] || r)}, for your actual column.
References:
Method: spreadsheets.values.get
Method: spreadsheets.values.update
Related
I am using Exceljs library to export data from the database using Nodejs, Now I am trying to set the column Header name dynamically from columns=36 (i.e. AK) to till the end or until it has data. but nothing helps.
column name strictly needs to start from 36th (i.e. AK) column name
labels array are like this -
[
'Type',
'Competition',
'IDB',
'SOV Focus',
'Medium',
'Tone'
]
So, I only need to print these in the header.
con.query(query, id, function (err, result) {
if (err) throw err;
const labels = [];
result.forEach((result) => {
labels.push(result.label);
});
labels.forEach((label, index) => {
const columnName = label;
// Get the column using the column index (in this case, 1)
const firstRow = worksheet.getRow(1);
// Set the value of the first cell in the row to the dynamic column name
firstRow.getCell(36, columnName);
});
});
But it is not working or throwing any errors.
Previously I used PHPSpreadhsheet in PHP but it was not able to handle huge data export and took much time to export data.
but in PHPspreadsheet it was so easy to set dynamic header names.
$sheet->setCellValueByColumnAndRow($col, 1, trim($labels[$k] , ','));
How will I set columns/header names dynamically?
I'm trying to update a column in users table the column type is json.
column name is test.
and the column consists of an object default value for example is
{a: "text", b: 0}
how to update let's say the object key b without changing the whole column
the code i'm using is
knexDb('users').where({
email: email
})
.update({
test: { b: 1 }
})
second solution
knexDb('users').where({
email: email
})
.update({
test: knexDb.raw(`jsonb_set(??, '{b}', ?)`, ['test', 1])
})
first solution changes the whole column cell and test will be only { b: 1 }
second solution doesn't work it give an error
function jsonb_set(json, unknown, unknown) does not exist
The expected result
is to manage to update only a certain key value in an object without changing the whole object.
PS
I also want to update an array that consists of objects like the above one for example.
[{a: "text", b: 0}, {c: "another-text", d: 0}]
if i use the code above in kenxjs it'll update the whole array to only {b: 1}
PS after searching a lot found that in order to make it work i need to set column type to jsonb, in order the above jsonb_set() to work
but now i'm facing another issue
how to update multiple keys using jsonb_set
knexDb('users').where({
email: email
})
.update({
test: knexDb.raw(`jsonb_set(??, '{b}', ?)`, ['test', 1]),
test: knexDb.raw(`jsonb_set(??, '{a}', ?)`, ['test', "another-text"]),
})
the first query key b is now not updating, in fact all updates don't work except the last query key a, so can some explain why ?
Your issue is that you're overwriting test. What you're passing into update is a JS object (docs). You cannot have multiple keys with identical values (docs). You'll have to do something like this where you make 1 long string with all your raw SQL as the value to test.
knexDb('users').where({
email: email
})
.update({
test: knexDb.raw(`
jsonb_set(??, '{a}', ?)
jsonb_set(??, '{b}', ?)
`,
['test', "another-text", 'test', 1])
})
Probably a better option exists - one that would be much more readable if you have to do this for several columns is something like what I have included below. In this example, the column containing the jsonb is called json.
const updateUser = async (email, a, b) => {
const user = await knexDb('users')
.where({ email })
.first();
user.json.a = a;
user.json.b = b;
const updatedUser = await knexDb('users')
.where({ email })
.update(user)
.returning('*');
return updatedUser;
}
Update/insert a single field in a JSON column:
knex('table')
.update( {
your_json_col: knex.jsonSet('your_json_col','$.field', 'new value')
})
.where(...)
Update/insert multiple fields
Option 1 (nested)
knex('table')
.update( {
your_json_col: knex.jsonSet(knex.jsonSet('your_json_col','$.field1', 'val1')
'$.field2', 'val2')
})
.where(...)
Option 2 (chained)
knex('table')
.update( {
your_json_col: knex.jsonSet('your_json_col','$.field1', 'val1')
})
.update( {
your_json_col: knex.jsonSet('your_json_col','$.field2', 'val2')
})
.where(...)
In my user edit route, I am trying to use the Lodash merge function to update the returned user document (from Mongoose) with the updates sent in req.body. Here is my code:
const { dobYear, dobMonth, dobDay } = req.body;
const dob = formatDob(dobYear, dobMonth, dobDay);
const user = await db.User.findById(req.params.id);
const updates = pick(req.body, [ 'fullName', 'email', 'password', 'gender', 'address', 'avatar_url' ]);
merge(user, [updates, dob]);
let updatedUser = await user.save();
The problem is even when I send an updated email in the request, the merge does not seem to actually overwrite the old email value with the new one (from updates).
You are trying to merge an object with an array in the way you are passing the arguments to merge.
See documentation. And I assume your confusion came from the fact that in the docs they have _.merge(object, [sources]). However if you see in the Arguments section they have:
[sources] (...Object): The source objects. Meaning a list of objects rather than an actual array.
Try this:
var user = { 'a': 1, 'b': 2 };
var updates = { 'a': 3, 'c': 4, 'email': 'aaa#bbb.com' };
let dob = '11-11-2019'
let result = _.merge(user, updates, {dob}); // <-- ...Object
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
merge(user, [updates, dob]);.
Incorrect usage. Accepts the following :
Arguments
object (Object): The destination object.
[sources] (...Object): The source objects.
Observe the..., that means it accepts a variable number of arguments.
merge(user, updates, { dob })
I am creating an API with SQL Server as the database. My tables and columns are using Pascal case (CountryId, IsDeleted, etc) that cannot be changed.
So when I do this:
const mssql = require('mssql');
var sqlstr =
'select * from Country where CountryId = #countryId';
var db = await koaApp.getDb();
let result = await db.request()
.input('countryId', mssql.Int, countryId)
.query(sqlstr);
My resulting object is
{
CountryId: 1,
CountryName: "Germany"
}
But I want it to be
{
countryId: 1,
countryName: "Germany"
}
I know there is a "row" event, but I wanted something more performant (since I may be returning several rows from the query, above is just an example).
Any suggestions?
PS: I want to avoid the FOR JSON syntax
Posting this as an actual answer, as it proved helpful to the OP:
if it's viable, you may try simply specifying the columns in the query as such:
select
CountryID countryId,
CountryName countryName
from
Country
where
CountryId = #countryId
Typically it's not best practice to use select * within queries anyways because of performance.
A simple explanation, putting a space and a new name (or perhaps better practice, within square brackets after each column name, such as CountryName [countryName] - this allows for characters such as spaces to be included within the new names) is aliasing the name with a new name of your choosing when returned from SQL.
I'd suggest using the lodash utility library to convert the column names, there is a _.camelCase function for this:
CamelCase documentation
_.camelCase('Foo Bar');
// => 'fooBar'
_.camelCase('--foo-bar--');
// => 'fooBar'
_.camelCase('__FOO_BAR__');
// => 'fooBar'
You can enumerate the result keys using Object.entries then do a reduce, e.g.
let result = {
CountryId: 1,
CountryName: "Germany"
};
let resultCamelCase = Object.entries(result).reduce((obj,[key,value]) => {
obj[_.camelCase(key)] = value;
return obj;
}, {});
console.log(resultCamelCase);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
I would like to query Excel for a range of cells and know whether there are merged cells within that range. I see that there is an API for merging cells and an API for unmerging cells. Does anyone know if it is possible to just check for merge cells?
Currently we don't have an API to query the state of merged cells.
Please log a feature request on UserVoice and we will take it into account for future API planning.
-Philip, Developer on the Office Extensibility team
Docs: https://learn.microsoft.com/en-us/javascript/api/excel/excel.range?view=excel-js-preview#getMergedAreasOrNullObject__
Note: This is still a WIP for me, would need a "isNull" check and I haven't adapted this for production code, but this should be a good starting point. I recommend examine the mergedAreas object if you need further details.
Here is how I did it:
async function Get_Merged_Areas_Arr_Of_Objs(context, ws) { //test for Null
var mergedAreas = ws.getUsedRange(true).getMergedAreasOrNullObject();
mergedAreas.load(["areas"]);
await context.sync()
var Merged_Areas_Arr_Of_Objs = []
var arrlen = mergedAreas.areas.items.length
for (var ai = 0; ai < arrlen; ai += 1) {
var obj = mergedAreas.areas.items[ai]
var rng_obj = {}
rng_obj['worksheet'] = obj['address'].split("!")[0]
rng_obj['rowIndex'] = obj['rowIndex']
rng_obj['columnIndex'] = obj['columnIndex']
rng_obj['rowCount'] = obj['rowCount']
rng_obj['columnCount'] = obj['columnCount']
Merged_Areas_Arr_Of_Objs.push(rng_obj)
}
return Merged_Areas_Arr_Of_Objs
}
var Merged_Areas_Arr_Of_Objs = await Get_Merged_Areas_Arr_Of_Objs(context,ws)
console.log('Merged_Areas_Arr_Of_Objs:')
console.log(Merged_Areas_Arr_Of_Objs)
[object Object],[object Object],[object Object],[object Object]
[
0: {
[functions]: ,
__proto__: { },
columnCount: 1,
columnIndex: 0,
rowCount: 3,
rowIndex: 1,
Symbol()_7.z1gk27bjwa1: undefined,
Symbol(nodejs.util.inspect.custom)_j.z1gk27bjwa1: undefined,
worksheet: "Sheet3"
},
1: { },
2: { },
3: { },
length: 4
]