hope everyone is fine, I have a tricky question, from an RPA app I get this object:
let data = {
Fecha: '2022-12-14T00:00:00',
Hora: '1899-12-31T16:14:00',
'Aten.': 73,
' Nro Ing ': 0,
Cerrada: 'S',
' ': ' ',
' Nombre Atenci¾n ': 'AMBULATORIA',
'EstadoHC.Electronica': ' - ',
Profesional: ' GARCIA CHAVERRA MADELEINE ',
Especialidad: ' MEDICINA GENERAL ',
Diagnostico: ' ENFERMEDAD CARDIACA, NO ESPECIFICADA ',
'Num.Cta': 0
}
As you can see, the key of the object, some of them are a little weird, what i want to do is replace the single quotes from the keys, to get the [Nombre Atenci¾n] value.
What I try is parser the object in a new object with JSON.parse and replace the spaces in the beginning and the end, like this:
let data2 = JSON.parse(JSON.stringify(data).replace(/"\s+|\s+"/g,'"'));
Then I try to iterate the second object, to get the specific value of the key mentioned before, after replace spaces and characters, but then I get undefined instead of "AMBULATORIA"
for(let dat in data2){
dat = dat.replace(/\s\s+/g, '').replace("¾", 'o');
console.log(dat.NombreAtencion)
}
Why I use a for to iterate "one single object" is because I get an array of objects like that one, so I have to use the same treatment to every object.
As you can see, the key of the object, some of them are a little weird, what i want to do is replace the single quotes from the keys
There are no single quotes in the object keys. In an object literal, you can put the name of the property in quotes (single or double). The quotes are just delimiters, not part of the property name. You only have to do that if the property name contains a character that isn't allowed in a property literal (which is true of all of your examples — spaces and . are perfectly valid in property names, but not property name literals).
So there's nothing to do, your object already has property names that don't have those quotes in them. You can tell by looking at the property names:
let data = {
Fecha: '2022-12-14T00:00:00',
Hora: '1899-12-31T16:14:00',
'Aten.': 73,
' Nro Ing ': 0,
Cerrada: 'S',
' ': ' ',
' Nombre Atenci¾n ': 'AMBULATORIA',
'EstadoHC.Electronica': ' - ',
Profesional: ' GARCIA CHAVERRA MADELEINE ',
Especialidad: ' MEDICINA GENERAL ',
Diagnostico: ' ENFERMEDAD CARDIACA, NO ESPECIFICADA ',
'Num.Cta': 0
};
console.log("Property names:");
for (const name of Object.keys(data)) {
console.log(name);
}
console.log("Value of property Aten.: ", data["Aten."]);
.as-console-wrapper {
max-height: 100% !important;
}
If you want to rationalize those property names so they're things you can use in property name literals (and so they follow the standard conventions for JavaScript property names), you could have a Map with the original name and the new name you'd like to use, and then create a new object with the new names for the properties:
let data = {
Fecha: "2022-12-14T00:00:00",
Hora: "1899-12-31T16:14:00",
"Aten.": 73,
" Nro Ing ": 0,
Cerrada: "S",
" ": " ",
" Nombre Atenci¾n ": "AMBULATORIA",
"EstadoHC.Electronica": " - ",
Profesional: " GARCIA CHAVERRA MADELEINE ",
Especialidad: " MEDICINA GENERAL ",
Diagnostico: " ENFERMEDAD CARDIACA, NO ESPECIFICADA ",
"Num.Cta": 0,
};
const nameMap = new Map([
["Fecha", "fecha"],
["Hora", "hora"],
["Aten.", "aten"],
[" Nro Ing ", "norIng"],
["Cerrada", "cerrada"],
[" ", "spaces"], // Or whatever
[" Nombre Atenci¾n ", "nombreAtencion"],
["EstadoHC.Electronica", "estadoHCElectronica"],
["Profesional", "profesional"],
["Especialidad", "especialidad"],
["Diagnostico", "diagnostico"],
["Num.Cta", "numCta"],
]);
const updated = Object.fromEntries(
Object.entries(data).map(([name, value]) => [nameMap.get(name) ?? name, value])
);
console.log(updated);
.as-console-wrapper {
max-height: 100% !important;
}
Or using a simple loop instead of Object.fromEntries, Object.entries, and map:
let data = {
Fecha: "2022-12-14T00:00:00",
Hora: "1899-12-31T16:14:00",
"Aten.": 73,
" Nro Ing ": 0,
Cerrada: "S",
" ": " ",
" Nombre Atenci¾n ": "AMBULATORIA",
"EstadoHC.Electronica": " - ",
Profesional: " GARCIA CHAVERRA MADELEINE ",
Especialidad: " MEDICINA GENERAL ",
Diagnostico: " ENFERMEDAD CARDIACA, NO ESPECIFICADA ",
"Num.Cta": 0,
};
const nameMap = new Map([
["Fecha", "fecha"],
["Hora", "hora"],
["Aten.", "aten"],
[" Nro Ing ", "norIng"],
["Cerrada", "cerrada"],
[" ", "spaces"], // Or whatever
[" Nombre Atenci¾n ", "nombreAtencion"],
["EstadoHC.Electronica", "estadoHCElectronica"],
["Profesional", "profesional"],
["Especialidad", "especialidad"],
["Diagnostico", "diagnostico"],
["Num.Cta", "numCta"],
]);
const updated = {};
for (const name of Object.keys(data)) {
const newName = nameMap.get(name) ?? name;
updated[newName] = data[name];
}
console.log(updated);
.as-console-wrapper {
max-height: 100% !important;
}
Or if you want to do it with some rules, here's an example treating . as a space, removing extraneous spaces, and converting to standard camelCase:
let data = {
Fecha: "2022-12-14T00:00:00",
Hora: "1899-12-31T16:14:00",
"Aten.": 73,
" Nro Ing ": 0,
Cerrada: "S",
" ": " ",
" Nombre Atenci¾n ": "AMBULATORIA",
"EstadoHC.Electronica": " - ",
Profesional: " GARCIA CHAVERRA MADELEINE ",
Especialidad: " MEDICINA GENERAL ",
Diagnostico: " ENFERMEDAD CARDIACA, NO ESPECIFICADA ",
"Num.Cta": 0,
};
function convertName(name) {
// Convert anything that isn't A-Za-z0-9_ to a space,
// and trim any leading/trailing spaces
name = name.replace(/[^\w]/g, " ").trim();
// If blank, bail early
if (!name) {
return "__unkown__";
}
// Split into words at a series of spaceds
let words = name.split(/ +/);
// Make the first word all lower-case, and make remaining words lower
// case except the first letter
words[0] = words[0].toLowerCase();
for (let n = 1; n < words.length; ++n) {
words[n] = words[n][0].toUpperCase() + words[0].substring(1).toLowerCase();
}
// Join the result
return words.join("");
}
const updated = Object.fromEntries(
Object.entries(data).map(([name, value]) => [convertName(name), value])
);
console.log(updated);
.as-console-wrapper {
max-height: 100% !important;
}
Or (again) using a simple loop instead of Object.fromEntries, Object.entries, and map:
let data = {
Fecha: "2022-12-14T00:00:00",
Hora: "1899-12-31T16:14:00",
"Aten.": 73,
" Nro Ing ": 0,
Cerrada: "S",
" ": " ",
" Nombre Atenci¾n ": "AMBULATORIA",
"EstadoHC.Electronica": " - ",
Profesional: " GARCIA CHAVERRA MADELEINE ",
Especialidad: " MEDICINA GENERAL ",
Diagnostico: " ENFERMEDAD CARDIACA, NO ESPECIFICADA ",
"Num.Cta": 0,
};
function convertName(name) {
// Convert anything that isn't A-Za-z0-9_ to a space,
// and trim any leading/trailing spaces
name = name.replace(/[^\w]/g, " ").trim();
// If blank, bail early
if (!name) {
return "__unkown__";
}
// Split into words at a series of spaceds
let words = name.split(/ +/);
// Make the first word all lower-case, and make remaining words lower
// case except the first letter
words[0] = words[0].toLowerCase();
for (let n = 1; n < words.length; ++n) {
words[n] = words[n][0].toUpperCase() + words[0].substring(1).toLowerCase();
}
// Join the result
return words.join("");
}
const updated = {};
for (const name of Object.keys(data)) {
const newName = convertName(name);
updated[newName] = data[name];
}
console.log(updated);
.as-console-wrapper {
max-height: 100% !important;
}
Related
I have looked at previous answers but cannot find a solution.
My state contains a deck of "color cards":
class App extends Component {
constructor() {
super()
this.allCards = ['#fca7f3 ', 'white', ' #6da740 ',' #f6faba ', ' #ccc5c1 ', ' #f7791f ', ' #575657 ', ' #03faf5 ', ' #13afdb ', ' #7509e2 ', ' #63522e ', ' #d809e2 ', '#060606', '#fd2f03',' #effa17 ',' #33fb2d ']
this.state = {currentDeck: [' #ccc5c1 ', ' #f7791f ', ' #575657 ', ' #03faf5 ',]}
}
This is updated with this function:
changeDifficulty = (e) => {
let newDeck = []
let howManyCards = e.target.value // this decides difficulty level
for (let i = 0; i < howManyCards; i++) {
newDeck.push(this.allCards[i])
}
this.setState({currentDeck: newDeck})
}
The state is successfully updating, however, the component below is not re-rendering after the first render:
<Game deck={this.state.currentDeck} />
So the number of cards on the screen remains the same as the default setting.
If I console.log newDeck before setting state, it shows the following, first after clicking Medium button, then after Hard.
Array(8) [ "#fca7f3 ", "white", " #6da740 ", " #f6faba ", " #ccc5c1 ", " #f7791f ", " #575657 ", " #03faf5 " ]
Array(12) [ "#fca7f3 ", "white", " #6da740 ", " #f6faba ", " #ccc5c1 ", " #f7791f ", " #575657 ", " #03faf5 ", " #13afdb ", " #7509e2 ", … ]
Your array reference is not updated in state when you write this,
this.setState({currentDeck: newDeck})
As the reference is not updated react renderer doesn't know about the update. What you need to do is create a new array and push that in state like this,
this.setState({currentDeck: [...newDeck]})
I'm trying to take a JSON Array and display the full output, but nicely formatted. (see commented out section) Unfortunately the JSON array returns back with OBJECT then its output. So I stringify to fix the [Object, Object] error I was getting. But now everything is on one line. How do iterate through the array and put them on new lines?
Second issue I'm having is, I can't do 3 of the same functions as you notice in the uncommented section. I'd like to take each result and add a new line in between them.
function setTitleStatus(context, settings) {
$SD.api.setTitle(context, "Updating...");
getResults(result => resultCallback(result, context));
}
function resultCallback(result, context) {
if (!result.hasOwnProperty("Object")) {
$SD.api.setTitle(context, JSON.stringify(result));
console.log(JSON.stringify(result, '%c%s'));
return;
}
// This is where I'd like all 3 objects to be split on new lines.
// $SD.api.setTitle(context, result.Platform.replace(new RegExp(' ', 'g'), '\n') +
// "\n" + result.Platform + " ")
// $SD.api.setTitle(context, result.PU.replace(new RegExp(' ', 'g'), '\n') +
// "\n" + result.PU + " ")
// $SD.api.setTitle(context, result.EA.replace(new RegExp(' ', 'g'), '\n') +
// "\n" + result.EA + " ")
}
function getResults(updateTitleFn) {
let endPoint = "https://status.robertsspaceindustries.com/static/content/api/v0/systems.en.json";
$.getJSON(endPoint)
.done(function (response) {
updateTitleFn({
"Platform": response[0].status,
"PU": response[1].status,
"EA": response[2].status,
});
console.log("Platform", response[0].status)
console.log("PU", response[1].status)
console.log("EA", response[2].status)
})
}
Update
If I uncomment the sections this is what it shows. Its hard to tell but whats happening is, its taking replacing setTitle three times, and taking the last line. $SD.api.setTitle(context, result.EA.replace(new RegExp(' ', 'g'), '\n') +
"\n" + result.EA + " ")
Via Screenshot
To get nicely formatted output from JSON.stringify, supply the optional arguments:
JSON.stringify(obj, null, 2)
let arr = ["Pineapple", "Lemon", "Apple", "Orange", "Peach"];
document.getElementById('result').innerHTML =
'Stringify default: ' + JSON.stringify(arr) + '\n\n' +
'Stringify formatted: ' + JSON.stringify(arr, null, 2);
<pre id="result"></pre>
I currently have an array of strings that are numbers
data.dataArr = [0: " 1,431,417 "
1: " 1,838,127 "
2: " 679,974 "
3: " 2,720,560 "
4: " 544,368 "
5: " 1,540,370 "]
I am attempting to remove the commas so my data returns 0: "1431417" , 1: 1838127 ...
After removing commas I am then mapping this array to convert it to an array of numbers and not strings. But when console.logging the finalArray that should return an array of numbers I am getting NaN I believe this is due to the part of removing the commas.
Here is my code:
let data = {
dataArr: [
" 1,431,417 ",
" 1,838,127 ",
" 679,974 ",
" 2,720,560 ",
" 544,368 ",
" 1,540,370 "
]
};
//removing commas
let arrData = data.dataArr.map(e => e.replace(/(,\s*)+/, ','));
let finalArr = arrData.map(Number);
console.log(finalArr)
alternatively I've tried :
let arrData = data.dataArr.replace(/,/g, "")
Which resulted in "data.dataArr.replace is not a function"
You can use number in same map callback function, g to remove all occurrence of ,
dataArr = [" 1,431,417 ", " 1,838,127 ", " 679,974 ", " 2,720,560 ", " 544,368 ", " 1,540,370 "]
let arrData = dataArr.map(e => Number(e.replace(/(,\s*)+/g, '').trim()));
console.log(arrData)
['1,234', '7,8,90,'].map(eachNo => {
return eachNo.split(',').join('')
});
Split() will split string where it will find ,(comma) and will return
an array of strings.
join() will operate on array of strings.
There also seems to be a space in your array which would be giving NaN, Remove everything other than digits and maybe a dot.
Try this regex:
e.replace(/[^\d.]/g, '');
Use Array.prototype.map()
const data = {};
data.dataArr = [
" 1,431,417 ",
" 1,838,127 ",
" 679,974 ",
" 2,720,560 ",
" 544,368 ",
" 1,540,370 ",
];
const numbersArray = data.dataArr.map(str => Number(str.replace(/\D/g, '')));
console.log(numbersArray)
Maybe like this:
var data = {};
data.dataArr =
[
" 1,431,417 ",
" 1,838,127 ",
" 679,974 ",
" 2,720,560 ",
" 544,368 ",
" 1,540,370 "
];
function array_to_numbers(_arr){
var out = [];
for(var key in _arr){
var el = _arr[key];
el = el.trim();
el = el.replace(new RegExp(',','g'), '');
el = parseInt(el)||0;
out.push(el);
}
return out;
}
console.log(array_to_numbers(data.dataArr));
You can .map() over the array and split up by , and then join them at "". You also need to wrap everything in Number to convert it to an number
let dataArr = [
" 1,431,417 ",
" 1,838,127 ",
" 679,974 ",
" 2,720,560 ",
" 544,368 ",
" 1,540,370 "
]
let result = dataArr.map(el => Number(el.split(",").join("")))
console.log(result)
let data = new Object();
data.dataArr = [ " 1,431,417 ",
" 1,838,127 ",
" 679,974 ",
" 2,720,560 ",
" 544,368 ",
" 1,540,370 "];
const finalArr = data.dataArr.map(x => x.replace(/[^0-9]/g, ''));
console.log(finalArr)
How do I do an update statement with knex.js where the returning data comes from more than one table. For example, how would I write this update query with knex.js?
update notes
set note = 'This is an updated1 note', timestamp = now()
from(select
id,
note,
user_id,
customer_id
from notes
where id = '46' AND user_id = 7) a
left join customers as b on a.customer_id = b.id
where notes.id = a.id
returning a.id, a.note, a.user_id, b.id;
I can write it to return data when only one table is used:
knex('notes')
.returning([
'notes.id',
'notes.note',
'notes.user_id AS userId',
'notes.customer_id AS customerId',
'notes.product_id AS productId',
'notes.timestamp',
])
.where('notes.id', noteId)
.update({
timestamp: new Date(),
note: req.body.note,
});
My problems start when I then try to introduce customers.
I also tried this:
const [note] = await db.sequelize.knex.raw(
'UPDATE notes '
+ 'SET note = ?, '
+ 'timestamp = NOW() '
+ 'FROM(SELECT id, '
+ 'note, '
+ 'user_id, '
+ 'customer_id '
+ 'FROM notes '
+ 'WHERE id = ? '
+ 'AND user_id = 7) AS a '
+ 'LEFT JOIN customers AS b ON a.customer_id = b.id '
+ 'WHERE notes.id = a.id '
+ 'RETURNING a.id, a.note, a.user_id, b.id', ['This is an updated1 note', 46]
);
but it gives me TypeError: (intermediate value) is not iterable.
UPDATE
I've now got this:
let note = await db.sequelize.knex.raw(
'UPDATE notes '
+ 'SET note = ?, '
+ 'timestamp = NOW() '
+ 'FROM(SELECT id, '
+ 'note, '
+ 'user_id, '
+ 'customer_id, '
+ 'product_id, '
+ 'timestamp '
+ 'FROM notes '
+ 'WHERE id = ? '
+ 'AND user_id = 7) AS a '
+ 'LEFT JOIN customers AS b ON a.customer_id = b.id '
+ 'LEFT JOIN products AS c ON a.product_id = c.id '
+ 'WHERE notes.id = a.id '
+ 'RETURNING a.id, a.note, a.user_id AS userId, a.customer_id AS customerId, a.product_id AS productId, a.timestamp, b.title AS customerName, b.code AS customerCode, c.title AS productName, c.code AS productCode', [req.body.note, noteId]
);
/*const [note] = await db.sequelize.knex('notes')
.returning([
'notes.id',
'notes.note',
'notes.user_id AS userId',
'notes.customer_id AS customerId',
'notes.product_id AS productId',
'notes.timestamp',
//'customers.title AS customerName',
//'customers.code AS customerCode',
//'products.title AS productName',
//'products.code AS productCode',
])
//.leftJoin('customers', 'notes.customer_id', 'customers.id')
//.leftJoin('products', 'notes.product_id', 'products.id')
.where('notes.id', noteId)
.update({
timestamp: new Date(),
note: req.body.note,
});*/
console.log('PC NOTE', note.rows);
[note] = note.rows;
return res.json({ note });
It returns this:
{
"note": {
"id": 46,
"note": "This is an updated2 note",
"userid": 7,
"customerid": 111781,
"productid": null,
"timestamp": "2019-07-12T19:37:23.996Z",
"customername": "PC CUSTOMER3",
"customercode": "PC003",
"productname": null,
"productcode": null
}
}
This is almost what I need except the returned keys are all lower case. How do I get userid, customerid, productid, customername, customercode, productname and productcode to appear in camel case like I stated in the RETURN part on my knex statement?
Knex doesn't have any special support for update + joins
https://github.com/tgriesser/knex/issues/2796
so writing raw query is your only choice.
This is what worked for me:
let note = await db.sequelize.knex.raw(
'UPDATE notes '
+ 'SET note = ?, '
+ 'timestamp = NOW() '
+ 'FROM(SELECT id, '
+ 'note, '
+ 'user_id, '
+ 'customer_id, '
+ 'product_id, '
+ 'timestamp '
+ 'FROM notes '
+ 'WHERE id = ? '
+ 'AND user_id = 7) AS a '
+ 'LEFT JOIN customers AS b ON a.customer_id = b.id '
+ 'LEFT JOIN products AS c ON a.product_id = c.id '
+ 'WHERE notes.id = a.id '
+ 'RETURNING a.id, '
+ 'notes.note, '
+ 'notes.user_id AS "userId", '
+ 'notes.customer_id AS "customerId", '
+ 'notes.product_id AS "productId", '
+ 'notes.timestamp, '
+ 'b.title AS "customerName", '
+ 'b.code AS "customerCode", '
+ 'c.title AS "productName", '
+ 'c.code AS "productCode"', [newNote, noteId],
);
[note] = note.rows;
return res.json({ note });
I'm trying to check if the team contains one of the following strings in the array. If yes then remove it. Why is it not doing this?
function changeName(name) {
var team = name;
var removearray = ['.CS', ' Dota2', '-Dota2', ' Esports', 'eSports', ' Tactics', 'DotCom', ' DotA2', ' - LoL', '-LoL', ' Carry', 'Â', ' LoL'];
removearray.forEach(function( word ) {
team = team.replace( new RegExp( word, 'g' ), '' );
});
return team;
}
Please note that "forEach" is not supported in certain browsers such as IE8.
Also, please consider the following implementation:
function changeName(name) {
var removearray = ['.CS', ' Dota2', '-Dota2', ' Esports', 'eSports', ' Tactics', 'DotCom', ' DotA2', ' - LoL', '-LoL', ' Carry', 'Â', ' LoL'];
return team = removearray.reduce(function(previous, current) {
return previous.replace( new RegExp( current, 'g' ), '' );
}, name);
}
The "reduce" method available in the Array Prototype in Javascript is a very nice way of doing tasks such as this one.
function changeName(name) {
var team = name;
var removearray = ['.CS', ' Dota2', '-Dota2',
' Esports', 'eSports', ' Tactics', 'DotCom',
' DotA2', ' - LoL', '-LoL', ' Carry', 'Â', ' LoL'];
for(var i = 0; i < removearray.length; i++){
while(team.indexOf(removearray[i]) > -1) {
var index = team.indexOf(removearray[i]);
if (index > -1) {
team = team.substr(0, index) +
team.substr(index + removearray[i].length);
}
}
}
return team;
}
var one = changeName('John'); // returns 'John'
var two = changeName('John Dota2 Doe'); // returns 'John Doe'
var three = changeName('John Dota2 Doe Dota2.CS') // returns 'John Doe'