I have the below code that allows me to log a specific Map() key to the console, but cannot produce any output using a for each:
let teamlist = new Map()
//code to populate the map
console.log(teamlist) //Shows entire map and data in console
console.log(teamlist[0]) //Shows one entry from the map
teamlist.forEach(team =>{
console.log(team) //Shows no console output, not even "undefined"
})
I assumed this was going to be an issue due to async, but doesn't make sense as I can call individual keys? Can I not call a forEach() on a map?
Your situation could happen if you didn't add items to the Map properly.
For example, if you did this:
let teamlist = new Map();
teamlist[0] = "hello";
Then, what you did there was add a [0] property to the teamlist object and did not add an entry to the Map itself. Remember, every Map object is also a regular Object and can have regular properties that are not part of the Map specific data structure. To add an item to a Map object, you must use the .set() method like this:
let teamlist = new Map();
teamlist.set("some greeting", "hello");
teamlist.set("another greeting", "goodbye");
teamlist.forEach(team => {
console.log(team);
});
Of course, if you show us the code you're using to actually add items to the Map object, then we can answer more specifically with specific corrections to that code.
Can I not call a forEach() on a map?
You can, but it only iterates items that are actually in the Map data structure.
I assumed this was going to be an issue due to async
You don't show us any asynchronous code at all. If you do have asynchronous code, then we can only comment on its correct use if you show us that actual code.
Related
I have a TSX file, with a state including:
tickets: Ticket[],
I now want to change one specific element inside the array, and reset the state, my idea:
onClick = (ticket: Ticket, i: number) => {
var newTitle = window.prompt('hello')
ticket.title = newTitle ? newTitle : ticket.title
var tickets = [this.state.tickets]
tickets[i] = ticket
// set state
}
Besides the usual "OBject could be undefined" errors, I'm mainly getting stuck at:
Type 'Ticket' is missing the following properties from type 'Ticket[]': length, pop, push, concat, and 28 more. TS2740
It's as if they still consider tickets[i] to be of type Tickets[]. (I've done other checks and that seems to be the problem).
Do you know why this is the case? And how can still achieve my goal?
Thank you
There's a lot that's wrong here including multiple mutations of state.
Array of Arrays
The particular error that you've posted:
Type 'Ticket' is missing the following properties from type 'Ticket[]': length, pop, push, concat, and 25 more.
Is caused by this line:
var tickets = [this.state.tickets]
You are taking the array of tickets from state and putting it into an array. This variable tickets is an array with one element where that element is the array from your state. In typescript terms, it is [Ticket[]] or Ticket[][]. So each element of that array should be Ticket[] instead of Ticket. When you try to set an element with a Ticket then you get an error that it should be Ticket[].
State Mutations
As a rule of thumb, don't mutate anything in React if you aren't certain that it's safe. Just setting ticket.title is an illegal mutation of state which will prevent your app from re-rendering properly. The Ticket object that is passed to onClick is (presumably) the same object as the one in your state so you cannot mutate it.
Instead, we use array.map (which creates a copy of the array) to either return the same Ticket object or a copied one if we are changing it. We don't actually need the ticket as an argument. If the tickets have some unique property like an id then you could also pass just the ticket and not i.
onClick = (i: number) => {
const newTitle = window.prompt("hello");
if (newTitle) {
this.setState((prevState) => ({
tickets: prevState.tickets.map((ticket, index) =>
index === i ? { ...ticket, title: newTitle } : ticket
)
}));
}
};
I want to use gremlin-javascript to traverse the remote graph and get a list of vertex, whose id is within a list of predefined ids.
const gremlin = require('gremlin');
const Graph = gremlin.structure.Graph;
const GraphPredicate = gremlin.process.P;
const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection;
const graph = new Graph();
const g = graph.traversal().withRemote(new DriverRemoteConnection('ws://localhost:8182/gremlin'));
g.V()
.has('id', GraphPredicate.within([414, 99999]))
.toList()
.then(function (result) {
console.log(result);
});
Above are the codes I have tried, but it gave me an empty list of vertex, whereas, I expected to have a vertex(414) in the result.
Moreover, when I tested with the gremlin-console by using the statement below, it gave me the vertex(414) in the result.
:> g.V().hasId(within(414,99999))
So I have some questions here:
Do I miss something in the configuration in order to use Predicate?
In the method of javascript GraphPredicate.within([414, 99999])) is the parameter supposed to be only an array of elements or a list of elements separated by a comma as in the case with gremlin-console? By the way, I have tried both ways, but I always got an empty result.
Thank you in advance,
The id is an special property in TinkerPop and can't be retrieved using the name property "id".
The correct way to retrieve by ids in your case should be:
g.V().hasId(P.within(414, 99999)).toList()
.then(result => console.log(result));
Additionally, this can be simplified by removing the within() call:
g.V().hasId(414, 99999).toList()
.then(result => console.log(result));
I can't comment, but in order to use id, you need to use gremlin.process.t.id
Example:
in Gremlin .by(id)
in JS .by(gremlin.process.t.id)
Hope this is helpful
I have
db.result('DELETE FROM categories WHERE id = ${id}', category).then(function (data) { ...
and
db.many('SELECT * FROM categories').then(function (data) { ...
initially delete is called from one API call and then select on following API call, but callback for db request happens in reverse order, so I get list of categories with removed category.
Is there a way how to lock categories table with pg-promise?
If you want the result of the SELECT to always reflect the result of the previous DELETE, then you have two approaches to consider...
The standard approach is to unify the operations into one, so you end up executing all your dependent queries against the same connection:
db.task(function * (t) {
yield t.none('DELETE FROM categories WHERE id = ${id}', category);
return yield t.any('SELECT FROM categories');
})
.then(data => {
// data = only the categories that weren't deleted
});
You can, of course, also use either the standard promise syntax or even ES7 await/async.
The second approach would be to organize an artificial lock inside your service that would hold off on executing any corresponding SELECT until the DELETE requests are all done.
However, this is a very awkward solution, typically pointing at the flaw in the architecture. Also, as the author of pg-promise, I won't be even getting into that solution, as it would be way outside of my library anyway.
I am working with the below piece of code in Microsoft Bot Framework to access the list of regexes for global commands. This code is a part of botbuilder module:
if (typeof session.conversationData.globalCommands === "undefined") {
// An array which contains the list of all global commands
session.conversationData.globalCommands = [];
// Accessing the list of global commands
globalActions = session.library.actions.actions;
lenGlobalActions = Object.keys(globalActions).length;
// Assigning values to the above list
for (var i=0; i<lenGlobalActions; i++){
session.conversationData.globalCommands.push(globalActions[Object.keys(globalActions)[i]].options.matches);
}
}
// Checking if the incoming message from the user is a global command
var isGlobalCommand = session.conversationData.globalCommands.some(regex => regex.test(session.message.text));
The issue here is, the code runs fine for the first time and the values assigned to the variable session.conversationData.globalCommands are in the form given below:
However, after the first execution, the array converts to the below without any changes made in the code anywhere else:
Due to this, the line:
var isGlobalCommand = session.conversationData.globalCommands.some(regex => regex.test(session.message.text));
throws an exception "regex.test is not a function".
I am unable to understand why this should be happening and how do I solve this as I need this list separately for some processing.
I believe you cannot store complex types in the bot store (conversationData, etc). The object needs to be serializable to JSON and I don't believe a RegExp it is.
The workaround would be to store the regex as an string and then recreate the regex object using the constructor and the stored string expression.
Check the core-State sample to know more about the store capabilities.
This is a really trivial problem. I am just curious on how to deal with this in a "professional" manner.
I am trying to stick to variable naming convention. For NodeJs I am doing camelCasing. For database, I am using PostgreSQL and using underscore_casing.
Now the problem arises when I query data from PostgreSQL. I'll get a user object with following format,
{user_id: 1, account_type : "Admin"}
I can pass this object directly to server side-render and will have to use underscore casing to access account_type. Of course, I can manually create a new user JSON object with property userId and accountType but that is unnecessary work.
Is it possible to follow variable naming convention for both language and avoid having mixed variable names casing in some files? What is a good way to stay organized?
The are two good ways to approach this issue. The simplest one - do no conversion, use the exact database names. And the second one is to camel-case columns automatically.
Either way, you should always follow the underscore notation for all PostgreSQL declarations, as it will give you the option to activate camel-casing in your app at a later time, if it becomes necessary. Never use camel-case inside the database, or you will end up in a lot of pain later.
If you want the best of both worlds, follow the underscore notation for all PostgreSQL declarations, and convert to camel-case as you read data.
Below is an example of how to do it properly with pg-promise, copied from event receive example:
// Example below shows the fastest way to camelize column names:
const options = {
receive(e) {
camelizeColumns(e.data);
}
};
function camelizeColumns(data) {
const template = data[0];
for (var prop in template) {
const camel = pgp.utils.camelize(prop);
if (!(camel in template)) {
for (var i = 0; i < data.length; i++) {
const d = data[i];
d[camel] = d[prop];
delete d[prop];
}
}
}
}
Also see the following article: Pg-promise and case sensitivity in column names.
UPDATE
The code above has been updated for use of pg-promise v11 or later.
I've struggled with this too, and I've concluded that there's really no way to avoid this kind of ugliness unless you rewrite the objects that come from the database. Fortunately, that's not too difficult in Javascript:
const fromDBtoJS = (obj) => {
// declare a variable to hold the result
const result = {};
// iterate over the keys on the object
Object.keys(obj).forEach((key) => {
// adjust the key
const newKey = key.replace(/_[a-z]/g, (x) => x[1].toUpperCase());
// add the value from the old object with the new key
result[newKey] = obj[key];
});
// return the result
return result;
};
Here's a JSFiddle. The "replace" code above was found here
If you wanted to use classes for models in your application, you could incorporate this code into the constructor or database load method so it's all handled more-or-less automatically.