Adding and appending value to an array with Realtime Database - javascript

I'm making a React.js app's where the user can upload a song to firebase and then he will see the queque with all the uploaded songs in order. Queque can be sorted with a drag and drop system, that will be update the database in Firebase. When uploading a songs, is there a way to insert that songs in an array? The schema will be:
project-name:
[0]:
- name
- artist
- duration
[1]:
- name
- artist
- duration
[ecc]
How can I add an array and then append items in the database?
I'm using nodejs for backend and socket.io to send new sorted queque to node.
uploadSongs.js:
queueRef.set()
queueRef.update({
...metas,
path: fileName,
}, (error) => {
if (error) {
console.log("Data could not be saved." + error)
} else {
console.log("Data saved successfully.")
}
})
songs.js:
io.on('connect', socket => {
var quequeRef = admin.database().ref()
quequeRef.on('value', function (snapshot) {
var queque = snapshot.val()
if (queque != null) {
var value = Object.values(queque)
io.emit('queueSongs', Object.values(value))
} else {
io.emit('queueSongs', [])
}
})
socket.on('queueSongs', (songs) => {
console.log(songs)
quequeRef.set(songs, (error) => {
if (error) {
console.log("Data could not be saved." + error)
} else {
console.log("Data saved successfully.")
}
})
})
})
Thanks

If I understand you correctly this is how I would do it.
You have an collection called que inside of your collection que you have documents.
when you add your information to your document you may want to add an key called orderId.
so this is how your document will look
{
orderId:0,
artist:'haddaway',
title:'baby dont hurt me'
}
So when you are fetching your data you do something like
db.collection('que').orderBy('orderId').get()
That way you will always get the order that you put them in.

Related

How to create/ update large quantity records in azure cosmos database

I have 1500 records to be created in azure cosmos database, I just loop through using Javascript code. I have REST API connection to the database. I feed the data to be updated as JSON array.
The problem is when I pass entire data, azure database timesout or send ECONNECTIONRESET. Many of you would create huge amount of records in the database and there is might be some efficient way to overcome this problem. I want your suggestion.
Since majority of records is not found, many times create new record part is hit and I have never pushed such huge amount of data before. Any suggestion or new idea will really help me.
Note : I run this javascript code using mocha unit test
Below is code snippet
Record.js
const fetch = require('node-fetch');
let connectionAzureDataBase = "abc...";
let SubscriptionKey = "xyz";
let promises = [];
let j = -1;
module.exports = {
checkRecord
}
function checkRecord (req) {
for (let i = 0; i < req.body.length; i++) {
promises[j] = new Promise(async function(resolve, reject) {
//check if record exist in azure
var apiUrl = APICheckRecord( req.body[i].recordName);
fetch(apiUrl , { headers:connectionAzureDataBase})
.then(res => res.json())
.then(record => {
if(record) {
console.log("Record Found");
} else {
console.log("Record not Found, calling API to create Record");
var apiUrl = APICreateNewRecord( req.body[i].recordName);
fetch(apiUrl , { headers:connectionAzureDataBase})
.then(res => res.json())
.then(recordCreated => {
if(recordCreated) {
console.log("record created successfully");
resolve("record created successfully");
} else {
console.log("Encountered some unexpected condition");
resolve("Encountered some unexpected condition");
}
}).catch(err => {
console.log("record could not be created");
resolve("record could not be created");
})
}
}).catch(err => {
console.log("record not found");
resolve("record not found");
})
})// close promise
}// close for
let replies = await Promise.all(promises);
let promise1 = new Promise (function(resolve,reject) {
resolve(replies);
})
}
Record.spec.js
const Records = require("Record.js);
it("should find/create records", async function() {
this.timeout(6000000);
try {
let req =[
{
"recordName": "Xyz",
"recordDate": "12-06-2020"
},
{
"recordName": "Abc",
"recordDate": "13-06-2020"
}
]
let reply = await Records.checkRecord(req);
console.log(JSON.stringify(reply));
} catch(err) {
console.log(err);
}
})
Error
message: 'request to https://apim-dev.azure-api.net/api/portal/records/?recordName="Xyz" failed, reason: read ECONNRESET',
type: 'system',
errno: 'ECONNRESET',
code: 'ECONNRESET' }
message: 'request to https://apim-dev.azure-api.net/api/portal/createRecords/ failed, reason: read ECONNRESET',
type: 'system',
errno: 'ECONNRESET',
code: 'ECONNRESET' }
This is sample of data that is passed, I have 1500 such records
SampleData
[
{
"recordName": "Xyz",
"recordDate": "12-06-2020"
},
{
"recordName": "Abc",
"recordDate": "13-06-2020"
}
]
You can use Azure Cosmos DB Data Migration tool, which can import data from various sources into Azure Cosmos containers. You can import from JSON files. You migrate that data to collections for use with Azure Cosmos DB. The Data Migration tool can also be used when migrating from a single partition collection to a multi-partition collection for the SQL API.
Import JSON files
The JSON file source importer option allows you to import one or more single document JSON files or JSON files that each have an array of JSON documents. When adding folders that have JSON files to import, you have the option of recursively searching for files in subfolders.

How to change order of mail folders?

I have this function for getting user folders.
function getUserFolders(callback) {
getAccessToken(function(accessToken) {
if (accessToken) {
// Create a Graph client
var client = MicrosoftGraph.Client.init({
authProvider: done => {
// Just return the token
done(null, accessToken);
}
});
// Get all folders
client
.api("/me/MailFolders")
.orderby("")
.get((err, res) => {
if (err) {
callback(null, err);
} else {
callback(res.value);
}
});
console.log(client);
} else {
var error = { responseText: "Could not retrieve access token" };
callback(null, error);
}
});
}
When I get a response back, the order of folders is:
I have read documentation and couldn't find how to change order of folders. The order i would like to have is the same one as on outlook. Thank you for your help!!
You cannot retrieve folders in the order a user organized them in a given client.
I'm also not sure what you expect to get from .orderby(""). Unless you provide a field to order by, it won't know how you want to sort them.

Angular 5 : Sending an array of HTTP request that need to be executed in sequential order

I am trying to send an array of HTTP requests which need to be executed in sequential order, but i have no clue on how to do that. Below are details of my application.
Application Entities :
Location - an entity which can has the following attributes:FanZone fanZone, List<LocationAdministrator> locationAdmins
FanZone - an entity which has the following attributes: List<FanZoneAdministrator> fanZoneAdmins
Idea:
By filling the form on the picture below, and clicking "NEXT" button, i am saving an Location object in one of my Angular services, because i dont want to POST it until the application user completes filling up administrator information ( form for filling in admin information is presented to the user after clicking on "NEXT" button ).
After application user successfully fills in the Location Information form presented on picture above, he has to fill in the information on Location Administrators and Fan Zone Administrators. The form is presented in the picture below.
When application user successfully fills in administrator forms presented in the picture above, I would like to register Location entity ( send POST request ), and AFTER that same Location entity has been posted to the Database, i want to send an array of HTTP POST requests in order to register list of LocationAdministrator and list of FanZoneAdministrator entities.
Angular code:
next() {
this.locationService.registerLocation(this.location).subscribe(
(response: Response) => {
console.log('Successfully registered Location!');
console.log(response.json());
},
(error: Response) => {
console.log('Error occured while trying to register new Location');
}
);
var fanZoneAdmin: User;
this.registerFanZoneAdminForm.get('fanZoneAdminArray').value.forEach(element => {
console.log(element);
fanZoneAdmin = new User(element.username,element.password,element.email,element.firstName,element.lastName,element.city,element.phoneNumber, null,null,null,null, null,this.location.fanZone,null,new Role("FZA"),null);
this.usersService.registerFanZoneAdmin(fanZoneAdmin).subscribe(
(response: Response) => {
console.log('Successfully registered Fan Zone Administrator!');
console.log(response.json());
},
(error: Response) => {
console.log('Error occured while trying to register new Fan Zone Administrator');
}
);
});
console.log('Submitting Location Administrator!')
var locationAdmin: Location;
this.registerLocationAdminForm.get('locationAdminArray').value.forEach(element => {
console.log(element);
locationAdmin = new User(element.username,element.password,element.email,element.firstName,element.lastName,element.city,element.phoneNumber, null, null,null, null, null,null,this.location, new Role("LA"),null);
this.usersService.registerLocationAdmin(locationAdmin).subscribe(
(response: Response) => {
console.log('Successfully registered Fan Zone Administrator!');
console.log(response.json());
},
(error: Response) => {
console.log('Error occured while trying to register new Fan Zone Administrator');
}
);
});
console.log('DONE!')
}
NOTE: this.registerFanZoneAdminForm.get('fanZoneAdminArray').value.forEach(element => {..}) is there because I used FormArray. Here value is an Array<FanZoneAdministrators> and element is single FanZoneAdministrator
(Same goes for registerLocationAdminForm.get('locationAdminArray').value.forEach(element=>{..}))
Sequence of HTTP requests should be like in the code : Location - > List of Fan Zone Administratos - > List of Location Administrators
Any kind of help will be appreciated!
You can send the next request once the response to the current request comes in.
Here is an example:
let fanZoneAdminArray = this.registerFanZoneAdminForm.get('fanZoneAdminArray').value;
let locationAdminArray = this.registerLocationAdminForm.get('locationAdminArray').value;
this.locationService.registerLocation(this.location).subscribe((response: Response) => {
fanZoneAdminRecursion(0, fanZoneAdminArray, () => {
locationAdminRecursion(0, locationAdminArray, () => {
// All requests were sent.
});
});
});
let fanZoneAdminRecursion = (index, array, onDone) => {
let fanZoneAdmin = new User(element.username,element.password,element.email,element.firstName,element.lastName,element.city,element.phoneNumber, null,null,null,null, null,this.location.fanZone,null,new Role("FZA"),null);
this.usersService.registerFanZoneAdmin(fanZoneAdmin).subscribe((response: Response) => {
if(index < array.length - 1){
fanZoneAdminRecursion(++index, array, onDone);
}else{
onDone();
}
});
}
let locationAdminRecursion = (index, array, onDone) => {
let locationAdmin = new User(element.username,element.password,element.email,element.firstName,element.lastName,element.city,element.phoneNumber, null, null,null, null, null,null,this.location, new Role("LA"),null);
this.usersService.registerLocationAdmin(locationAdmin).subscribe((response: Response) => {
if(index < array.length - 1){
locationAdminRecursion(++index, array, onDone);
}else{
onDone();
}
});
}
Here I'm using recursion to call a function that processes the next element in the array once the response for the previous element comes in.
This can be made a lot less complex using Promise. With promises, this will be as easy as Promise.all(firstCall, secondCall, ....).

How to reuse fetched data from API?

I'm fetching data from a API that returns a JSON object:
fetch("api.php")
.then(function(response) {
console.log("Status: " + response.status);
if (response.ok) {
return response.json();
} else {
throw Error(response.status);
}
}).then(function(json) {
json.forEach(function(item) {
// 'datas' contains the items extracted from the JSON response
datas.add(item);
});
}).catch(function(err) {
console.log(error);
});
If I want to query the data with jinqJs I can change the code slightly to:
}).then(function(json) {
var result = new jinqJs()
.from(json)
.where('start_date = 2017-03-10')
.select();
result.forEach(function(item) {
datas.add(item);
});
}).catch(function(err) {
and it works really well.
My question is: due to the fact that by fetching only once the API I actually download ALL the needed data how can I query it 'outside' the forEach fetch?. I mean: I already have all the data with one call to the API, I can easily do queries on the data with jinqJs why should I call the API every time I need to query it? Is it possible to query datas once the forEach has added all the items?
For example, outside the forEach (notice the .from(datas) instead of .from(json)) I could do:
var result = new jinqJs()
.from(datas)
.where('start_date = 2017-03-10')
.select();
and get the same result.
As I'm trying to build a mobile app, this would be handy because I would bind the above code to specific buttons and query the data accordingly and I would connect to the internet only the first time the app is started rather than every time a query is needed.
Assign the "JSON" promise to a variable
var something = fetch("api.php")
.then(function(response) {
console.log("Status: " + response.status);
if (response.ok) {
return response.json();
} else {
throw Error(response.status);
}
});
Now you can use something as many times as you like
something
.then(json => console.log(json))
.catch ...
something.then(json => new jinqJs()
.from(json)
.where('start_date = 2017-03-10')
.select()
.forEach(function(item) {
datas.add(item);
});
).catch ....

AWS Lambda function processes same dynamodb stream multiple times. What am I missing?

I have written a node.js lambda function that triggers based on a dynamodb stream when new records are inserted into a particular table.
The function receives only new events, filters for inserted records, and then for each record, uses a couple of fields to retrieve data from other tables. Using this combined data a message is composed and sent via SNS to specific target ARN.
The function performs correctly. All the relevant data is retrieved, and a push notification is sent out.
However, for some reason the function appears to be called several times for the same stream, and processes the newly inserted records several times. The result is the target device receiving the same push notification several times.
Should I be placing the callback in a different place, or am I not calling on the context correctly?
This is the function:
'use strict';
var AWS = require("aws-sdk");
var dynamodb = new AWS.DynamoDB();
var sns = new AWS.SNS();
console.log('Loading function');
exports.handler = (event, context, callback) => {
console.log('Received event:', JSON.stringify(event, null, 2));
event.Records.forEach((record) => {
console.log(record.eventID);
console.log(record.eventName);
console.log('DynamoDB Record: %j', record.dynamodb);
if (record.eventName == 'INSERT') {
var matchId = record.dynamodb.NewImage.eventId.S;
var match_params = {
Key: {
"eventId": {
S: matchId
}
},
TableName: "xxxxxxxxxxx-mobilehub-xxxxxxx-Event"
};
//retrieve the match information from Event table
dynamodb.getItem(match_params, function(err, data) {
var match_description = "";
if (err) {
console.log(err, err.stack);
context.fail('No match event record found in Event table');
} else {
match_description = data.Item.description.S;
var uId = record.dynamodb.NewImage.participantUserId.S; //participantUserId
var user_params = {
Key: {
"userId": {
S: uId
}
},
TableName: "xxxxxxxxxxx-mobilehub-xxxxxxxxx-User"
};
//retrieve the user record from User table
dynamodb.getItem(user_params, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
context.fail('Error occurred. See log.');
} else {
console.log(data); // successful response
if (data.length === 0) {
console.log("No User Record Found.");
context.fail('No user found for participantUserId.');
} else {
var deviceARN = data.Item.device_arn.S;
if (deviceARN <= 1) {
console.log("User has not registered their device for push notifications.");
context.fail('User has not registered for notifications');
} else {
var json_message = JSON.stringify({
APNS_SANDBOX: JSON.stringify({
aps: {
alert: "You are playing in an upcoming match " + match_description,
badge: 1,
sound: 'default'
}
})
});
var snsparams = {
Message: json_message,
MessageStructure: 'json',
TargetArn: deviceARN
};
sns.publish(snsparams, function(err, data) {
if (err) {
console.log(err); // an error occurred
context.fail('SNS send failed. See log.');
} else {
console.log(data); // successful response
context.success('Push notification sent to user.');
}
});
}
}
}
});
}
});
}
});
callback(null, `Successfully processed ${event.Records.length} records.`);
};
In my case, I added the same event source multiple times.
Quote from the conversation with an AWS support engineer:
Using my internal tools, I noticed that the Lambda function xxxxxx has
the event source:
arn:aws:events:my_region:my_acct_id:rule/my_event_target
configured twice as push event source. This means that this might be the cause
why you are seeing two invokes at every minute. Would you please
confirm on your side if this event is configured twice for the $LATEST
version of your lambda and also confirm if it's intended?
I hope this could save someelse :)
In your lambda page at the bottom, try tweaking "Concurrency" Unreserved account concurrency to 1 and "Asynchronous invocation" Retry attempts to 0 . As a test try these and observe the behaviour. Might help.

Categories

Resources