Wasted 3 hours already - trying to run transaction in firebase but it always fails with maxretry.
Basically my flow is:
On client:
call firebase http cloud funciton using js sdk.
On server:
read data from data base
update/invalidate data if needed
write the data back using transaction
The problem - step 4 always fail with maxretry.
The simplified code:
exports.myMethod2 = functions.https.onCall((data, context) => {
utilsModule.throwIfNoAuth(context);
return methodWithTransaction(context, admin);
});
exports.methodWithTransaction = function (context, admin) {
//this is called only once from outside!
return rootRef.child("my/data/path").once("value")
.then(function (indexRef) {
var usageObj = indexRef.val();
//update object's state
usageObj =
{
timestampUtcArray: [1530656089821, 1530656089822],
itemsCount: 2,
writeTimestamp: 1530656502759
}
return usageObj;
})
.then(function (usageObj) {
//her eis the sad part...
return rootRef.child("my/data/path").transaction(data => {
//this method always run 25 times and fails.
//data aways != usageObj though accross the calls usageObj are the same as well data are the same:
// usageObj =
// {
// timestampUtcArray: [1530656089821, 1530656089822],
// itemsCount: 2,
// writeTimestamp: 1530656502759 <-- only timestamp is different
// }
// data =
// {
// timestampUtcArray: [1530656089821, 1530656089822],
// itemsCount: 2,
// writeTimestamp: 1530656503421 <-- only timestamp is different
// }
return usageObj;
}
})
}
Any input s much appreciated as this seems to be a trivial task but I just stuck...
Related
Consider the following exerpt from this example in the InfluxDB documentation:
const fluxObserver = {
next(row, tableMeta) {
const o = tableMeta.toObject(row)
console.log(
`${o._time} ${o._measurement} in ${o.region} (${o.sensor_id}): ${o._field}=${o._value}`
)
},
error(error) {
console.error(error)
console.log('\nFinished ERROR')
},
complete() {
console.log('\nFinished SUCCESS')
}
}
/** Execute a query and receive line table metadata and rows. */
queryApi.queryRows(fluxQuery, fluxObserver)
The fluxObserver defines a sequence of operations at different stages of execution of the query, all of which are just console.log calls. I can imagine that people want to do something similar in a way that is actually useful, like for instance return an array that contains the result of the query, instead of logging something to a console. My problem is that queryApi.queryRows does not actually return anything, so it is not possible to do something like:
...
complete() {
console.log('\nFinished SUCCESS')
return data;
}
}
/** Execute a query and receive line table metadata and rows. */
var result = queryApi.queryRows(fluxQuery, fluxObserver);
return result;
So how can I return the data collected by the fluxObserver?
question is possibly a duplicate but I haven't found anything that provides an appropriate answer to my issue.
I have an ExpressJS server which is used to provide API requests to retrieve data from a MongoDB database. I am using mongoosejs for the MongoDB connection to query/save data.
I am building a route that will allow me to find all data that matches some user input but I am having trouble when doing the query. I have spent a long while looking online for someone with a similar issue but coming up blank.
I will leave example of the code I have at the minute below.
code for route
// -- return matched data (GET)
router.get('/match', async (req, res) => {
const style_data = req.query.style; // grab url param for style scores ** this comes in as a string **
const character_data = req.query.character; // grab url param for character scores ** this comes in as a string **
// run matcher systems
const style_matches = style_match(style_data);
res.send({
response: 200,
data: style_matches
}); // return data
});
code for the query
// ---(Build the finder)
const fetch_matches_using = async function(body, richness, smoke, sweetness) {
return await WhiskyModel.find({
'attributes.body': body,
'attributes.richness': richness,
'attributes.smoke': smoke,
'attributes.sweetness': sweetness
});
}
// ---(Start match function)---
const style_match = async function (scores_as_string) {
// ---(extract data)---
const body = scores_as_string[0];
const richness = scores_as_string[1];
const smoke = scores_as_string[2];
const sweetness = scores_as_string[3];
const matched = [];
// ---(initialise variables)---
let match_count = matched.length;
let first_run; // -> exact matches
let second_run; // -> +- 1
let third_run; // -> +- 2
let fourth_run; // -> +- 3
// ---(begin db find loop)---
first_run = fetch_matches_using(body, richness, smoke, sweetness).then((result) => {return result});
matched.push(first_run);
// ---(return final data)---
return matched
}
example of db object
{
_id: mongoid,
meta-data: {
pagemd:{some data},
name: whiskyname
age: whiskyage,
price: price
},
attributes: {
body: "3",
richness: "3",
smoke: "0",
sweetness: "3",
some other data ...
}
}
When I hit the route in postman the JSON data looks like:
{
response: 200,
data: {}
}
and when I console.log() out matched from within the style match function after I have pushed the it prints [ Promise(pending) ] which I don't understand.
if I console.log() the result from within the .then() I get an empty array.
I have tried using the populate() method after running the find which does technically work, but instead of only returning data that matches it returns every entry in the collection so I think I am doing something wrong there, but I also don't see why I would need to use the .populate() function to access the nested object.
Am I doing something totally wrong here?
I should also mention that the route and the matching functions are in different files just to try and keep things simple.
Thanks for any answers.
just posting an answer as I seem to have fixed this.
Issue was with my .find() function, needed to pass in the items to search by and then also a call back within the function to return error/data. I'll leave the changed code below.
new function
const fetch_matches_using = async function(body, richness, smoke, sweetness) {
const data = await WhiskyModel.find({
'attributes.body': body,
'attributes.richness': richness,
'attributes.smoke': smoke,
'attributes.sweetness': sweetness
}, (error, data) => { // new ¬
if (error) {
return error;
}
if (data) {
console.log(data)
return data
}
});
return data; //new
}
There is still an issue with sending the found results back to the route but this is a different issue I believe. If its connected I'll edit this answer with the fix for that.
I'm work with NodeJS and Sequelize. I have the following issue:
Read the Settings Table:
Settings.findOne({where: {
user_id: data
}})
.then(settings => {
// Next request
});
I need to save the settings.device (Example) outside of the .then block.
But if I do that like
var device;
Settings.findOne({where: {
user_id: data
}})
.then(settings => {
device = settings.device;
});
It doesn't work.
Already the error output undefined
The output in .then result block with console.log(settings.device); works perfect.
Update
I need it like:
var array = [];
// Get Settings from table
Settings.findOne({where: {
user_id: data
}})
.then(settings => {
// Get token from other Table
Example.findOne({where: {
user_id: data
}})
.then(example => {
// push to array
array.push({
"user_id" : data,
"device":settings.device, // output: settings.device is undefined
"token": example.token
});
});
});
// Send array to client
This is really a question of how to handle multiple resolved values in a Promise chain. You can search for that and see lots of great examples on how to handle it. For example, you could return an array or object in each then handler, or re-assign values to higher-scoped variables (as you're doing with settings). I've used both methods heavily in the past, and the resulting code is obviously inelegant and not fun to write.
However, async/await is readily available in Node and simplifies your code quite a bit:
const array = [];
// Get settings.
const settings = await Settings.findOne({where: {
user_id: data
}});
// Get token.
const example = await Example.findOne({where: {
user_id: data
}});
array.push({
user_id : data,
device: settings.device,
token: example.token
});
Sequelize return the model object you can get value by dataValue
console.log(settings.dataValues.device);
or if you want lean data
Settings.findOne({where: {
user_id: data,
raw:true,
}})
.then(settings => {
device = settings.device;
console.log(device);
});
Problem Intro:
In my React app I'm making some API calls to Github to fetch some user data. In another function I call these functions and wait for it with Axios's .all() method.
I want to fetch the data and do something with it using .then() but the returned value is just an array with 2 times undefined
What is the expected thing to happen:
It should return me 2 player objects with profile infos in the profile key of the object and a score value in the score key of the object.
What is my app doing in a nutshell?
It fetches the data from 2 usernames and they can "battle" each other. It just fetches the score and the followers and returns a sum. At the end it (should) returns an array with 2 player objects already sorted with the winner in the first place (exampleArray[0]).
General information's
It's an react app using components. It's really about one very tiny component and the helper functions in another file.
Here is where I call my custom function (the one returning undefined):
componentDidMount() {
const players = queryString.parse(this.props.location.search); //<== the usernames
const playersArray = [players.playerOneName, players.playerTwoName];
console.log(playersArray); // <== this logs the output as expected (an array with 2 usernames)
battle(playersArray).then((data) => { // <== the function it's all about
console.log(data); // <== data is => [undefined, undefined];
})
}
Next is the battle function from above that uses 2 other functions:
battle
export function battle(players) { // <== players aray with 2 usernames as string
return axios.all(players.map(getUserData)) // <== look 1 function below
.then(sortPlayers) // <== two functions below
.catch(handleError)
}
getUserData
let getUserData = (player) => {
axios.all([
getProfile(player),
getRepos(player)
]).then((data) => {
return {
profile: data[0],
score: calculateScore(data[0], data[1])
}
})
}
sortPlayers
let sortPlayers = (players) => {
return players.sort((a, b) => {
return b.score - a.score;
})
}
Ok so they also use other functions but they are really not too complicated. Let me know when you need examples from the other little helpers too.
I tried it with placing the debugger in different spots in the code and console logged different things, but I can't come through (first time I'm really working with promises). Sitting now 2 hours in front of this tiny problem and I can't figure it out.
I think the problem lies somewhere in battle function itself or getUserData
At the end a little screenshot, what the output of my console.log looks: http://prntscr.com/hz5abq
Thanks in advance
You don't have anything being returned in getUserData . Either add a return or remove the {} wrapping axios.all
let getUserData = (player) => {
return axios.all([
getProfile(player),
getRepos(player)
]).then((data) => {
return {
profile: data[0],
score: calculateScore(data[0], data[1])
}
})
}
getUserData needs to return the promise that it creates. At the moment it's not returning anything, so an implicit undefined is returned, and thus players.map(getUserData) results in an array of [undefined, undefined]
Ie, do this:
let getUserData = (player) => {
// VVV added return statement
return axios.all([
getProfile(player),
getRepos(player)
]).then((data) => {
return {
profile: data[0],
score: calculateScore(data[0], data[1])
}
})
}
I'm trying to deserialize a paginated end point. The return request for this end point looks like
{
count: number,
next: string,
previous: string,
data: Array[Objects]
}
The issue I'm having when using js-data to do a findAll, it's injecting this object into the data store. It should be injecting the objects in the data array into the store. So I made a deserialize method on my adapter that looks like this.
deserialize: (resourceConfig:any, response:any) => {
let data = response.data;
if (data && 'count' in data && 'next' in data && 'results' in data) {
data = data.results;
data._meta = {
count: response.data.count,
next: response.data.next,
previous: response.data.previous
};
}
return data;
}
And this works. The array objects are getting injected into my data store. But the meta information is getting lost.
dataStore.findAll('User').then(r => console.log(r._meta)); // r._meta == undefined
I would like to keep that meta information on the returned object. Any ideas?
To do this in v3 you just need to override a couple methods to tweak JSData's
handling of the response from your paginated endpoint. The two most important
things are to tell JSData which nested property of the response are the records
and which nested property should be added to the in-memory store (should be the
same nested property in both cases).
Example:
const store = new DataStore({
addToCache: function (name, data, opts) {
if (name === 'post' && opts.op === 'afterFindAll') {
// Make sure the paginated post records get added to the store (and
// not the whole page object).
return DataStore.prototype.addToCache.call(this, name, data.results, opts);
}
// Otherwise do default behavior
return DataStore.prototype.addToCache.call(this, name, data, opts);
}
});
store.registerAdapter('http', httpAdapter, { 'default': true });
store.defineMapper('post', {
// GET /posts doesn't return data as JSData expects, so we've got to tell
// JSData where the records are in the response.
wrap: function (data, opts) {
// Override behavior of wrap in this instance
if (opts.op === 'afterFindAll') {
// In this example, the Post records are nested under a "results"
// property of the response data. This is a paginated endpoint, so the
// response data might also have properties like "page", "count",
// "hasMore", etc.
data.results = store.getMapper('post').createRecord(data.results);
return data
}
// Otherwise do default behavior
return Mapper.prototype.wrap.call(this, data, opts);
}
});
// Example query, depends on what your backend expects
const query = { status: 'published', page: 1 };
posts.findAll(query)
.then((response) => {
console.log(response.results); // [{...}, {...}, ...]
console.log(response.page); // 1
console.log(response.count); // 10
console.log(response.hasMore); // true
});