I am trying to write a function that will:
Create documents in a sub collection
Allow for a then/catch call back after all sub documents have been created
export const doCreateSubs = (Id, count) => {
if (count > 0 && count <= 50){
const times = n => f => {
let iter = i => {
if (i === n) return;
f(i);
iter(i + 1);
};
return iter(0);
};
times(count)(i => {
db
.collection("parent")
.doc(`${Id}`)
.collection("sub")
.add({
subName: `name ${i + 1}`,
dateCreated: new Date()
});
});
}
}
I've played around with batch but it doesn't work with .collection. I know my function is really poor - is there a generally bettery way of doing this?
So i've just realised you can .doc() with no value and it will create a uid for the key. I can also return .commit and recieve a call back when it's complete!
export const doCreateSubs = (Id, count) => {
if (count > 0 && count <= 50){
const times = n => f => {
let iter = i => {
if (i === n) return;
f(i);
iter(i + 1);
};
return iter(0);
};
const batch = db.batch();
times(count)(i => {
const ref = db
.collection("parent")
.doc(`${Id}`)
.collection("subs")
.doc();
batch.set(ref, {
boxName: `Sub ${i + 1}`,
dateCreated: new Date()
});
});
return batch.commit();
}
}
Related
I try to insert multiple rows in React Native using SQLite.
this is the code:
rows = responseJson.rows;
for (i = 0; i < rows.length; i++) {
row=rows[i];
query = `insert into ComuniUserAccountSync values (
${row.IDComuniUserAccountSync},
${row.IdAzienda},
${row.IdComune},
${row.IdUserAccount},
'${row.DescrizioneComune}',
'${row.DateLastUpdateMaster}'
)`;
db.transaction(
tx => {
tx.executeSql(query, [], (a,b) =>
console.log("!OK!!", JSON.stringify(b)), (a, b) =>
console.log("!ERROR!!", a, b)
)
}
);
}
but the result is that I insert only the last row, many times! This is the output with
db.transaction(
tx => {
tx.executeSql("select IDComuniUserAccountSync from ComuniUserAccountSync", [], (a,b) =>
console.log("!OK!", JSON.stringify(b)), (a,b) =>
console.log("!ERROR!!", JSON.stringify(b))
);
}
);
!OK! {"rowsAffected":0,"rows":{"_array":[{"IDComuniUserAccountSync":72},{"IDComuniUserAccountSync":72},{"IDComuniUserAccountSync":72},{"IDComuniUserAccountSync":72},{"IDComuniUserAccountSync":72}, .......
ANY HELP??
Max
insertCategories(arrCateData){
let keys = Object.keys(arrCateData[0])
let arrValues = []
var len = arrCateData.length;
for (let i = 0; i < len; i++) {
arrCateData[i].image = `"${arrCateData[i].image}"`;
arrCateData[i].thumbnail = `"${arrCateData[i].thumbnail}"`;
arrCateData[i].name = `"${arrCateData[i].name}"`;
arrCateData[i].path = `"${arrCateData[i].path}"`;
arrValues.push("(" + Object.values(arrCateData[i]) +")");
}
// console.log(arrValues)
return new Promise((resolve) => {
this.initDB().then((db) => {
db.transaction((tx) => {
tx.executeSql("INSERT INTO category ("+ keys + ") VALUES " + String(arrValues)).then(([tx, results]) => {
resolve(results);
});
}).then((result) => {
this.closeDatabase(db);
}).catch((err) => {
console.log(err);
});
}).catch((err) => {
console.log(err);
});
});
}
this code may help you i just pass my array into function and it will insert data jusr change data according to ur requirement
I'm trying to crawl movie data from TMDB website. I finished my code with pure javascript, but I want to change the code into functional programming style by using ramda.js.
I attached my code below. I want to get rid of for-loop (if it is possible) and use R.pipe function.
(async () => {
for (let i = 0; i < 1000; i++) {
(() => {
setTimeout(async () => {
let year = startYr + Math.floor(i / 5);
await request.get(path(year, i % 5 + 1), async (err, res, data) => {
const $ = cheerio.load(data);
let list = $('.results_poster_card .poster.card .info .flex a');
_.forEach(list, (element, index) => {
listJSON.push({
MovieID: $(element).attr('id').replace('movie_', ''),
Rank: (i % 5) * 20 + index + 1,
Year: year
});
});
if(i === 1000 - 1) {
await pWriteFile(`${outputPath}/movieList.json`, JSON.stringify(listJSON, null, 2));
}
});
}, 1000 * i);
})(i);
}
})().catch(error => console.log(error));
Steps:
1- Break your code in small functions
2- Stop using async await and use promise.then(otherFunction)
3- When using promise, you could create a sleep function like these: const sleep = (time) => new Promise(resolve => setTimeout(resolve, time));
Ex.:
const process = index => sleep(1000)
.then(() => makeRequest(index))
.then(processData);
R.range(0, 1000)
.reduce(
(prev, actual) => prev.then(() => process(actual),
Promise.resolve()
) // Sequential
.then(printResult);
R.range(0, 1000)
.map(process) // Parallel
.then(printResult);
You can use the Ramda range() function to replace your loop.
https://ramdajs.com/docs/#range
R.range(0, 1000);
That will provide you with a collection of integers (your i) that you can work with (map() or whatever you need).
In childSnapshot.val().k I have this with cloud function:
{ '-LdmZIlKZh3O9cR8MOBU':
{ id: 'ceccomcpmoepincin3ipwc',
k: 'test',
p: 'somepath',
t: 1556700282278,
u: 'username' },
'-Llkocp3ojmrpemcpo3mc':
{ id: '[epc[3pc[3m,',
k: 'test2',
p: 'somepath2',
t: 1556700292290,
u: 'username2' }
}
I need each path value so I can delete that file from storage. How to access this value?
My cloud function for refreshing states, removing and deleting files from storage:
var db = admin.database();
var ref = db.ref('someref');
ref.once("value").then((snapshot) => {
var updates = {};
var patObject = {
fid: null,
ft: null,
ftr: null,
fu: null,
id: null,
lid: null,
lt: null,
ltr: null,
lu: null,
t: null,
tr: null,
v: null,
g: null,
l: null,
k: null
};
snapshot.forEach((childSnapshot) => {
if(childSnapshot.numChildren() >= 14){
var t = childSnapshot.val().t;
if((t===1 || t===5) && childSnapshot.val().tr > 0) {
if(childSnapshot.val().tr - 12 > 0){
updates[childSnapshot.key + '/tr'] = childSnapshot.val().tr - 12;
if(childSnapshot.val().k !== ""){
console.log('path: ', childSnapshot.val().k);
childSnapshot.val().k.snapshot.forEach(kpath => {
console.log('path: ', "path");
});
}
} else {
updates[childSnapshot.key] = patObject;
}
}
if(childSnapshot.val().tr<=0){
updates[childSnapshot.key] = patObject;
}
} else {
updates[childSnapshot.key] = patObject;
}
});
ref.update(updates);
res.send("");
return "";
}).catch(reason => {
res.send(reason);
})
return "";
If you want to delete all the files corresponding to the values of the ps, you need to use Promise.all() to execute in parallel the asynchronous deletion tasks (Since the delete() method returns a Promise). You need to iterate over the object that contains the p paths.
It is not easy to understand your code, so you'll find below the part corresponding to the above explanations. It's up to you to integrate it in your code!
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const defaultStorage = admin.storage(); //Note this line
//.....
exports.date = functions.https.onRequest((req, res) => { //I understand that you use an HTTP Cloud Function
//....
.then(...
// Somehow you get the object you mention in your question, through childSnapshot.val().k
const kObject = childSnapshot.val().k;
const bucket = defaultStorage.bucket(yourFileBucket);
const promises = [];
Object.keys(kObject).forEach(
//The values of the path p are obtained via kObject[key].p
//Based on that we push the Promise returned by delete() to the promises array
promises.push(bucket.file(kObject[key].p).delete());
);
return Promise.all(promises)
.then(results => {
//Here all the Promises that were in the promises array are resolved, which means that all the files are deleted
res.send({result: results.length + ' files(s) deleted'});
})
.catch(error => {
res.status(500).send(error);
});
});
Watch may be interested by watching the following official Firebase video by Doug Stevenson: https://youtu.be/7IkUgCLr5oA
Here is my code
var employeeList = [] ;
let db = SQLite.openDatabase({name: 'test.db', createFromLocation : "~example.db", location: 'Library'}, false,false);
db.transaction((tx) => {
tx.executeSql('SELECT * FROM Employees', [], (tx, results) => {
console.log("Query completed");
var len = results.rows.length;
for (let i = 0; i < len; i++) {
let row = results.rows.item(i);
employeeList.push(row.name);
}
this.setState({employees:employeeList});
db.closeDatabase();
});
});
alert(this.state.employees);
I am able to set result to employeeList inside a transaction.But When I am checking employeeList outside the transaction,it is getting blank...
What I have to do to set results.row to employees object..
It's asynchronous. You're asking for a value before the DB transaction has been performed. You need to use promises or callbacks to know when the query has executed.
As Gabriel mentioned, you need to wrap the call in a Promise. I provided an example of how you might want to do it.
const getEmployees = new Promise(function(resolve, reject) {
var employeeList = [] ;
let db = SQLite.openDatabase({name: 'test.db', createFromLocation : "~example.db", location: 'Library'}, false,false);
db.transaction((tx) => {
tx.executeSql('SELECT * FROM Employees', [], (tx, results) => {
console.log("Query completed");
var len = results.rows.length;
for (let i = 0; i < len; i++) {
let row = results.rows.item(i);
employeeList.push(row.name);
}
db.closeDatabase();
// resolve promise
resolve(employeeList)
});
});
getEmployees.then(data => {
this.setState({
employees:employeeList
})
})
Hi I have 3 tables of which, each one is child of another. I wrote a method to fetch from sqllite db as follows
public downloadFromOfflineDB(db,testSO){
var observableBatch = [];
observableBatch.push(db.executeSql("select * from TMP_AUD WHERE CRE_BY=? AND AUD_NUMBER=? ",
[localStorage.getItem("user_name"), testSO.auditNumber]).then(
response => {
this._util.logData('In downloadPendingInstancesForSyncFromOfflineDB- folder'+response.rows.length+'ID= '+response.rows.item(0).FLD_NUMBER);
if (response && response.rows && response.rows.length > 0) {
if (response && response.rows && response.rows.length > 0) {
var FLD_NUMBER = response.rows.item(0).FLD_NUMBER;
var folderArray = []
observableBatch.push(db.executeSql("select * from TMP_FOLDER WHERE CRE_BY=? AND FLD_NUMBER=? ",
[localStorage.getItem("user_name"), FLD_NUMBER]).then(
a => {
this._util.logData('In downloadPendingInstancesForSyncFromOfflineDB-TMP_FOLDER'+a.rows.length);
if (a && a.rows && a.rows.length > 0) {
for (let i = 0; i < a.rows.length; i++) {
var folderObj = {
folderName: a.rows.item(i).FLD_NAME,
files:[]
}
var FLD_NAME = a.rows.item(i).FLD_NAME
this._util.logData('In downloadPendingInstancesForSyncFromOfflineDB-TMP_FOLDER '+FLD_NAME);
observableBatch.push( db.executeSql("select * from TMP_FILES WHERE CRE_BY=? AND FLD_NAME=? ",
[localStorage.getItem("user_name"), FLD_NAME]).then(
b => {
this._util.logData('In downloadPendingInstancesForSyncFromOfflineDB-TMP_FILES'+b.rows.length);
var fileArray = [];
if (b && b.rows && b.rows.length > 0) {
for (let j = 0; j < b.rows.length; j++) {
var fileSO = {
compliance: b.rows.item(j).COMPLIANCE,
remarks: b.rows.item(j).REMARKS,
fileName: b.rows.item(j).FILE_NAME,
title: b.rows.item(j).TITLE
}
);
fileArray.push(fileSO);
}}
folderObj.files=fileArray;
}).catch(
e => {
this._util.logData('For sync error'+JSON.stringify(e));
return Observable.throw("An error occurred during sync");
})
);
folderArray.push(folderObj);
}}
}).catch(
e => {
this._util.logData('For sync error'+JSON.stringify(e));
return Observable.throw("An error occurred during sync");
})
);
}
}
testSO.folderArray = folderArray;
this._util.logData('Candidate for selected for sync' + JSON.stringify(testSO));
})
);
return Observable.forkJoin(observableBatch);
}
The issue here is below method is not waiting for all the calls to finish
public getFiles(testSO) {
return Observable.create(observer => {
this.platform.ready().then(() => {
this.sqlite.create({
name: 'offline.db',
location: 'default'
}).then((db: SQLiteObject) => {
this.downloadFromOfflineDB(db, testSO).subscribe(c => {
observer.next(c[0]);//This is undefined
observer.complete();
},
error => {
observer.error("An error occurred sync files.");
});
});
});
});
}
First method is executing, while second method returns before first execution is complete and I am not getting my object testSO populated. Can someone please guide me and tel me what I am doing wrong here.I used observable fork Join.
Looks like you are calling Observable.forkJoin(observableBatch) with only one item - result of db.executeSql. When you add more items later on it doesn't affect forkJoin.