Google Sheets API: insert formatted text - node.js

I am trying to insert bolded text into Google Spreadsheet. I have the following NodeJS code that inserts the text successfully.
var body = {
data: [{
range: 'M2:M3',
values: [["value1"],["value2"]]
}],
valueInputOption: 'USER_ENTERED',
};
var sheets = google.sheets('v4');
sheets.spreadsheets.values.batchUpdate({
auth: auth,
spreadsheetId: SPREADSHEET_ID,
resource: body
}, function(err, response) {
if (err) {
console.log('The API returned an error: ' + err);
return;
}
});
I looked up and found that in order to change the text format to bold, the following code needs to be used.
requests: [
{
"format": {
"textFormat": {
"bold": true
}
}
}
]
However, I cannot understand where this code should go. Tried putting requests as well as format separately inside data and batchUpdate but it did not work.

How about this sample script? If you want to update cell values and cell format, simultaneously, you can use spreadsheets.batchUpdate. The detail information is here.
The following sample imports [["value1"],["value2"]] to 'M2:M3' as shown in your script. As a sample, Sheet id is 0. The range is required to be inputted the GridRange.
Sample script :
var sheets = google.sheets('v4');
var request = {
spreadsheetId: SPREADSHEET_ID,
resource: {
"requests": [
{
"updateCells": {
"rows": [
{
"values": [
{
"userEnteredValue": {
"stringValue": "value1"
},
"userEnteredFormat": {
"textFormat": {
"bold": true
}
}
}
]
},
{
"values": [
{
"userEnteredValue": {
"stringValue": "value2"
},
"userEnteredFormat": {
"textFormat": {
"bold": true
}
}
}
]
}
],
"range": {
"sheetId": 0, // Sheet id
"startColumnIndex": 12,
"endColumnIndex": 13,
"startRowIndex": 1,
"endRowIndex": 3
},
"fields": "*"
}
}
]
},
auth: auth,
};
sheets.spreadsheets.batchUpdate(request, function(err, response) {
if (err) {
console.error(err);
return;
}
console.log(JSON.stringify(response, null, 2));
});
If I misunderstand your question, I'm sorry.

Related

Unable to retrive ordered job list from Google Transcoder API

i'm using the node.js client library of google transcoder api. I'm able to retrive a paginated list of some jobs, but i'm not able to order elements by start date. Here my codes:
const { TranscoderServiceClient } = require('#google-cloud/video-transcoder').v1;
class TranscoderApiController {
constructor() {
this.projectId = process.env.GOOGLE_CLOUD_PROJECT;
this.location = process.env.TASK_LOCATION;
}
async getEntries(req, res, next) {
const params = {
pageSize: req.query.pageSize ? parseInt(req.query.pageSize) : 10,
pageToken: req.query.pageToken,
filter: req.query.filter,
orderBy: req.query.orderBy
}
const client = new TranscoderServiceClient();
const result = await client.listJobs({
parent: client.locationPath(this.projectId, this.location),
pageSize: params.pageSize,
orderBy: 'createTime.seconds'
}, {
autoPaginate: false
});
if (result.length == 3 && result[2] != undefined) {
return result[2];
} else {
return result[1];
}
}
}
module.exports = new TranscoderApiController();
When i call the getEntries method i receive the following error:
"3 INVALID_ARGUMENT: The request was invalid: sort order \"createTime.seconds\" is unsupported"
If i remove the orderBy: 'createTime.seconds' line then the api works but is not ordered as i want. The result is something like that (i abbreviate the json):
{
"jobs": [
{
"labels": {},
"name": "projects/<id>/locations/europe-west1/jobs/<uuid>",
"inputUri": "",
"outputUri": "",
"state": "SUCCEEDED",
"createTime": {
"seconds": "1656602896",
"nanos": 386772728
},
"startTime": {
"seconds": "1656602900",
"nanos": 755000000
},
"endTime": {
"seconds": "1656603062",
"nanos": 428000000
},
"ttlAfterCompletionDays": 30,
"error": null,
"config": {
"inputs": [
{
"key": "input0",
"uri": "gs://<url>/render_md.mp4",
"preprocessingConfig": null
}
],
"editList": [...],
"elementaryStreams": [...],
"muxStreams": [...],
"manifests": [],
"adBreaks": [],
"spriteSheets": [],
"overlays": [],
"output": {
"uri": "gs://<url>/md.mp4/"
},
"pubsubDestination": {
"topic": "projects/<id>/topics/transcoder_api"
}
},
"jobConfig": "config"
},
...
],
"unreachable": [],
"nextPageToken": "Co8BCjgKDGV1cm9wZS13ZXN0MRIZdHJhbnNjb2Rlci5nb29nbGVhcGlzLmNvbRgBII..."
}
As you can see each job have the startTime.seconds property. I follow the syntax described here:
https://google.aip.dev/132#ordering
Any support to solve the ordered issue is appreciated.

Add information to a spreadsheet from the Google API

I have a Typescript and Node project in which I am trying to insert the information I get from the database into the spreadsheet using the Google API V4
https://sheets.googleapis.com/v4/spreadsheets/{spreadsheetId}:batchUpdate
This is the JSON object that I get from the database:
let sheetData = [
{
"country":null,
"age":25,
"fileName":"testName1"
},
{
"country":"Spain",
"age":null,
"fileName":"testName2"
}
]
I transform it with papaparse:
const papa = require("papaparse")
let result = papa.unparse(sheetData, {
header: false,
delimiter: ';',
encoding: 'UTF-8',
})
console.log(result)
This is what I get:
;25;testName1
Spain;;testName2
This is the xml that I use from the API to add the information:
{
"requests": [
{
"pasteData": {
"coordinate": {
"sheetId": 123,
"rowIndex": 2,
"columnIndex": 1
},
"delimiter": ";",
"type": "PASTE_VALUES",
"data": ";25;testName1Spain;;testName2"
}
}
]
}
I attach a screenshot with the result of the sheet:
My problem: All the information is put in the same row, how do I have to modify the array to include line breaks and be identified by the API?
This is the JSON that works from the API by adding \n:
{
"requests": [
{
"pasteData": {
"coordinate": {
"sheetId": 123,
"rowIndex": 2,
"columnIndex": 1
},
"delimiter": ";",
"type": "PASTE_VALUES",
"data": ";25;testName1\nSpain;;testName2"
}
}
]
}
This is the result I want to achieve, but I don't know how to treat the JSON with the information I get:
I thought that in your script, how about the following sample script?
Sample script:
const sheets = google.sheets({ version: "v4", auth }); // Please use your authorization script.
let sheetData = [
{
country: null,
age: 25,
fileName: "testName1",
},
{
country: "Spain",
age: null,
fileName: "testName2",
},
];
let result = papa.unparse(sheetData, {
header: false,
delimiter: ";",
encoding: "UTF-8",
});
console.log(result);
const requests = {
requests: [
{
pasteData: {
coordinate: {
sheetId: 123, // Please set your sheet ID.
rowIndex: 2,
columnIndex: 1,
},
delimiter: ";",
type: "PASTE_VALUES",
data: result,
},
},
],
};
sheets.spreadsheets.batchUpdate(
{
spreadsheetId: "###", // Please set your Spreadsheet ID.
resource: requests,
},
(err, result) => {
if (err) {
console.log(err);
return;
}
console.log(result.data);
}
);
In this modification, your value of result is used as the data of pasteData request.
When I tested this script, I confirmed that your expected result can be obtained.

Traversing array and changing object values

I'm trying to update the values ​​of my payments array objects
{
"balance": 109610,
"gifts": [],
"orders": [],
"payments": [{
"isPaid": 0,
"status": "Pending",
"address": "3KsdQbmADyz1KNN7qqX1yZcMXBbfFCm31r",
"date": 1624057559970
}, {
"isPaid": 0,
"status": "Pending",
"address": "3FYQK6YiAaL8fEbDWaXYw38CJN3K2y5dPD",
"date": 1624058531601
}],
"isVendedor": false,
"isAdmin": true,
"createdAt": {
"$date": "2021-06-17T21:10:15.020Z"
},
"username": "teste",
"email": "teste#teste.com",
"password": "$2a$10$qUNkorDuvbf.AYLTvjNc4ebKyNgLa7L9NoTBwAIV8.BfN51umaD9O",
"__v": 3
}
First, I look for the object of the user who made a request to my server
const userPayment = await User.find({"payments.address": notification.address}).exec();
Then I go through the user object and find it until I find the position where I find notification.address again
userPayment.forEach((AllPayments, index) => {
AllPayments.payments.forEach((payment, index) => {
if (payment.address == notification.address) {
if (payment.isPaid || payment.status != "Pending")
return res.json({
success: false,
error: "Payment Already Processed!",
});
const valueToDeposit = Math.round(notification.fiat_amount);
console.log(
userPayment[0].payments[index].isPaid,
userPayment[0].payments[index].status
);
// Set payments[index].isPaid = true
// Set payments[index].status = "Paid"
});
});
So I tried to make these 3 ways and none of them was successful.
userPayment[0].balance += valueToDeposit; // this works when save() is triggered
userPayment[0].payments[index].isPaid = 1; // this doesnt works when save() is triggered
userPayment[0].payments[index].status = "Paid"; // this doesnt works when save() is triggered
userPayment[0].updateOne({"payments.address": notification.address}, { $set: { "payments.$.isPaid": 1,"payments.$.status":"Paid" } },(err, result) => { console.log(err, result); }); this doesnt works
userPayment[0].save()

Payload Syntax for batchUpdate

I am using the googleapis module in a Node application. I was using version 21 but have just updated to version 52 due to a security vulnerability in the older version.
There are several breaking changes. I have overcome most except for formatting a date/time string. Is the following payload correct for formatting a date/time value in cell A11?
const formatDate = (next) => {
sheets.spreadsheets.batchUpdate({
auth: authClient,
spreadsheetId: sheetId,
requestBody: {
requests: [{
"repeatCell": {
range: { sheetId: 0, startRowIndex: 10, endRowIndex: 11, startColumnIndex: 0, endColumnIndex: 1},
cell: { userEnteredFormat: { numberFormat: { "type": "DATE_TIME", "pattern": "ddd yyyy-mm-dd hh:mm" } } },
fields: "userEnteredFormat.numberFormat"
}
}]
}
}, (err, response) => {
// ...
next();
}
);
}
No errors were returned with the above payload, but the formatting is not taking place. Is the key requestBody? Previously I was using resource.
I used async to perform authentication before formatting the date:
const authClient = new google.auth.JWT(client_email, null, private_key, SCOPES, null);
const sheetId = "1vgiEnV8fU_MrnIy31fbPAzhHz.......";
function authenticate(next) {
authClient.authorize((err) => {
next(err);
}
}
const tasks = [ authenticate, insertRow, formatdate ];
require("async").series(tasks);
Code for insertRow is not included here, but that works without problem.
I think that your script is correct. The cell format of "A11" is modified with the request body. And in this case, the request body can be used for both requestBody and resource.
But please confirm the following points, again.
sheetId of spreadsheetId: sheetId, is required to be the Spreadsheet ID.
In this case, when =now() is put to the cell "A11" and run the script, you can see the modified cell format.
By the following modification, you can check the returned values from Sheets API.
sheets.spreadsheets.batchUpdate(
{
auth: authClient,
spreadsheetId: "spreadsheetId", // <--- Please check this.
requestBody: {
requests: [
{
repeatCell: {
range: {
sheetId: 0,
startRowIndex: 10,
endRowIndex: 11,
startColumnIndex: 0,
endColumnIndex: 1,
},
cell: {
userEnteredFormat: {
numberFormat: {
type: "DATE_TIME",
pattern: "ddd yyyy-mm-dd hh:mm",
},
},
},
fields: "userEnteredFormat.numberFormat",
},
},
],
},
},
(err, res) => {
if (err) {
console.log(err);
return;
}
console.log(res.data);
}
);
Note:
In my environment, I tested your script with googleapis#52.1.0, and I could confirm the script worked.
This modified script supposes that your authorization process for using Sheets API has already been done.
References:
googleapis for Node.js
Method: spreadsheets.batchUpdate
RepeatCellRequest
Added:
Sample script for testing:
const client_email = "###"; // Please set here.
const private_key = "###"; // Please set here.
const spreadsheetId = "###"; // Please set here.
const { google } = require("googleapis");
let jwtClient = new google.auth.JWT(
client_email,
null,
private_key,
["https://www.googleapis.com/auth/spreadsheets"]
);
jwtClient.authorize((err) => {
if (err) console.log(err);
});
const sheets = google.sheets({ version: "v4", auth: jwtClient });
sheets.spreadsheets.batchUpdate(
{
spreadsheetId: spreadsheetId,
requestBody: {
requests: [
{
repeatCell: {
range: {
sheetId: 0,
startRowIndex: 10,
endRowIndex: 11,
startColumnIndex: 0,
endColumnIndex: 1,
},
cell: {
userEnteredFormat: {
numberFormat: {
type: "DATE_TIME",
pattern: "ddd yyyy-mm-dd hh:mm",
},
},
},
fields: "userEnteredFormat.numberFormat",
},
},
],
},
},
(err, res) => {
if (err) {
console.log(err);
return;
}
console.log(res.data);
}
);

How to build a search endpoint in a API to find and filter results from a database

In my Node API and MongoDB, I'm trying to build an endpoint to search for data in the DB and get back the results to the client. My search goal is to show results from the Profile collection and in that way, I can build my queries to search by first name, surname, company and the combination of it as an example:
GET search?fn=joe or ?ln=doe or ?cp=Company or ?fn=...&ln=...&cp=...
Practically I can search in different ways and I can get for example all the people working for a company as a result of a search.
I would like to understand how can I achieve that with Mongoose/MongoDB and add also to the query optional a limit/pagination for the coming results.
I tried to make some simple trials but I got stuck as I do not really get it how to proceed next.
const SearchController = {
async getQuery(req, res) {
try {
const { fn, ln, cp } = req.query;
const searchResult = await Profile.find({
$or: [
{ firstname: fn },
{ surname: ln },
{
experience: {
company: cp
}
}
]
});
res.status(200).json(searchResult);
} catch (err) {
res.status(500).json({ message: err.message });
}
}
};
The JSON of a profile:
{
"imageUrl": "https://i.pravatar.cc/300",
"posts": [
"5e3cacb751f4675e099cd043",
"5e3cacbf51f4675e099cd045",
"5e3cacc551f4675e099cd046"
],
"_id": "5e2c98fc3d785252ce5b5693",
"firstname": "Jakos",
"surname": "Lemi",
"email": "lemi#email.com",
"bio": "My bio bio",
"title": "Senior IT developer",
"area": "Copenhagen",
"username": "Jakos",
"experience": [
{
"image": "https://via.placeholder.com/150",
"createdAt": "2020-02-04T13:47:37.167Z",
"updatedAt": "2020-02-04T13:47:37.167Z",
"_id": "5e3975f95fbeec9095ff3d2f",
"role": "Developer",
"company": "Google",
"startDate": "2018-11-09T23:00:00.000Z",
"endDate": "2019-01-05T23:00:00.000Z",
"area": "Copenhagen"
},
{
"image": "https://via.placeholder.com/150",
"createdAt": "2020-02-04T13:59:27.412Z",
"updatedAt": "2020-02-04T13:59:27.412Z",
"_id": "5e3978bf5e399698e20c56d4",
"role": "Developer",
"company": "IBM",
"startDate": "2018-11-09T23:00:00.000Z",
"endDate": "2019-01-05T23:00:00.000Z",
"area": "Copenhagen"
},
{
"image": "https://via.placeholder.com/150",
"createdAt": "2020-02-07T16:35:43.754Z",
"updatedAt": "2020-02-07T16:35:43.754Z",
"_id": "5e3d91dfb3a7610ec6ad8ee3",
"role": "Developer",
"company": "IBM",
"startDate": "2018-11-10T00:00:00.000Z",
"endDate": "2019-01-06T00:00:00.000Z",
"area": "Copenhagen"
}
],
"createdAt": "2020-01-25T19:37:32.727Z",
"updatedAt": "2020-02-04T23:14:37.122Z",
"__v": 0
}
The expected results are for example if I search the first name Joe I should get back all the profiles having as first name Joe. Similar for surname and company.
Please provide comments to allow me to understand if you need more scripts from the original code to see.
EDITED added the code modified of the search
// Models
const { Profile } = require("../models");
// Error handling
const { ErrorHandlers } = require("../utilities");
const SearchController = {
async getQuery(req, res) {
try {
const { fn, ln, cp } = req.query;
const query = {
$or: []
};
if (fn) query.$or.push({ firstname: fn });
if (ln) query.$or.push({ surname: ln });
if (cp) query.$or.push({ "experience.company": cp });
const searchResult = Profile.find(query, docs => {
return docs
});
if ((await searchResult).length === 0)
throw new ErrorHandlers.ErrorHandler(
404,
"Query do not provided any result"
);
res.status(200).json(searchResult);
} catch (err) {
res.status(500).json({ message: err.message });
}
}
};
module.exports = SearchController;
Have tried conditional query and modified your array search query for finding the company,
function findUser(fn, ln, cp) {
const query = {
$or: []
}
if (fn) query.$or.push({ firstname: fn })
if (ln) query.$or.push({ surname: ln })
if (cp) query.$or.push({ "experience.company": cp })
Profile.find(query, function (err, docs) {
if (err) {
console.error(err);
} else {
console.log(docs);
}
});
}
findUser("","","IBM")

Resources