I am trying to save a JSON data to Firestore.
The data is as follows:
[{"back":"democracy","delayed_till":{"seconds":1574944200,"nanoseconds":0},"examples":[{"answer":"en Espana existe democracia desde 1975","example":"There is democracy in Spain since 1975"},{"answer":"Debemos luchar por nuestra democracia","example":"We must fight for our democracy"}],"front":"la democracia"},{"back":"habit, custom","delayed_till":{"seconds":1575148500,"nanoseconds":0},"front":"la costumbre"},{"back":"krokodil","delayed_till":{"seconds":1577831400,"nanoseconds":0},"front":"roos"},{"back":"krokodil","front":"blabla"},{"back":"bjkla","front":"blabla"}]
saving it to Firestore in the following does not work because the JSON data is stored in an array
db.collection('cardsb').add(object)
Using the following only saves the first object within the JSON data.
db.collection('cardsb').add(object[0])
The part that will be saved is the following:
{"back":"democracy","delayed_till":{"seconds":1574944200,"nanoseconds":0},"examples":[{"answer":"en Espana existe democracia desde 1975","example":"There is democracy in Spain since 1975"},{"answer":"Debemos luchar por nuestra democracia","example":"We must fight for our democracy"}],"front":"la democracia"}
How can I get the whole data to be saved in one document?
EDIT
This is how the JSON data is created:
cons () {
const nbrGroups = this.cards.length
for (let i = 0; i < nbrGroups; i++) {
var object = []
const nbrItems = this.cards[i].group.length
for (let item = 0; item < nbrItems; item++) {
var inputs = document.querySelectorAll('#' + this.cards[i].group_name.replace(/\s/g, '') + item + 'A #inFront, #' + this.cards[i].group_name.replace(/\s/g, '') + item + 'A #inBack, #' + this.cards[i].group_name.replace(/\s/g, '') + item + 'A #inAnswer, #' + this.cards[i].group_name.replace(/\s/g, '') + item + 'A #inExample')
const examples = []
if (inputs.length !== 2) {
for (let i = 2; i < inputs.length; i++) {
examples.push({ answer: inputs[i + 1].value, example: inputs[i].value })
i++
}
object.push({
back: inputs[1].value,
delayed_till: this.cards[i].group[item].delayed_till,
examples,
front: inputs[0].value
})
} else {
object.push({
back: inputs[1].value,
delayed_till: this.cards[i].group[item].delayed_till,
front: inputs[0].value
})
}
}
console.log(JSON.stringify(object))
console.log(JSON.stringify(object) === JSON.stringify(this.cards[i].group))
console.log(JSON.stringify(this.cards[i].group))
console.log(JSON.stringify(this.cards[i].id))
db.collection('cardsb').add(object[0])
}
This is how it should be stored in FB:
This is what actually is stored
As far as I can see you're just writing the data to Firestore too early. You should only write once you've processes all groups, and at that point should write them all at one.
So something like:
const nbrGroups = this.cards.length
var object = []; // Move this before the for loop
for (let i = 0; i < nbrGroups; i++) {
const nbrItems = this.cards[i].group.length
for (let item = 0; item < nbrItems; item++) {
var inputs = document.querySelectorAll('#' + this.cards[i].group_name.replace(/\s/g, '') + item + 'A #inFront, #' + this.cards[i].group_name.replace(/\s/g, '') + item + 'A #inBack, #' + this.cards[i].group_name.replace(/\s/g, '') + item + 'A #inAnswer, #' + this.cards[i].group_name.replace(/\s/g, '') + item + 'A #inExample')
const examples = []
if (inputs.length !== 2) {
for (let i = 2; i < inputs.length; i++) {
examples.push({ answer: inputs[i + 1].value, example: inputs[i].value })
i++
}
object.push({
back: inputs[1].value,
delayed_till: this.cards[i].group[item].delayed_till,
examples,
front: inputs[0].value
})
} else {
object.push({
back: inputs[1].value,
delayed_till: this.cards[i].group[item].delayed_till,
front: inputs[0].value
})
}
}
}
db.collection('cardsb').add(object[0]); // move this after the for loop
Just stringify the JSON before you send it, it will be stored as strings in firestore and when you need to retrieve it back you just need to parse it.
Example.
const jsonArray = JSON.stringify({
foo: bar,
sam: mas,
hello: "world",
createdAt: Date.now()
})
await firebase.firestore()
.collection('COLLECTION_NAME')
.doc("DOC_ID")
.update({
arrayField: firebase.firestore.FieldValue.arrayUnion(jsonArray)
})
.then(async (resp) => { })
.catch((error) => {
console.log(error.code)
});
This way you will save the json data as string inside array field in firestore
when you need to retrieve it back all you have to do is to use JSON.parse
JSON.parse(fieldName)
your data will be store like this picture
Related
this is my first post, i am a javascript newbie, and english is not my native language, so sorry if i my explanations are not as you expect.
So, i am trying to populate a select list with the result of an ajax database query.
the query returns a string:
'[["Saphir","1","10"],["Serval","2","10"],["Sygma","3","10"],["Swan","4","10"]]'
My purpose is to use this result to populate a select list with e.g. for the first option:
Saphir as the text, and "1" for the value.
Here is my last code, no error returned by the Chrome console.
I have tried to adapt so many others found here and there, but i still didn't succeed yet.
this code fills a list, but doesn't allow any selection.
#bfLabel410is the select list ID
function ff_sidefab_action(element, action) {
switch (action) {
case 'change':
jQuery.ajax(
{
type: "POST",
url: "/BMWK1census/ajaxsidemodelist.php",
data: { code: ff_getElementByName('sidefab').value },
success: function (data) {
var obj = JSON.parse(data);
console.log(obj);
var result = [];
var keys = Object.keys(obj);
console.log(typeof keys)
keys.forEach(function (key) { result.push(obj[key]); });
jQuery('#bfLabel410').empty();
jQuery('#bfLabel410').append(jQuery('<option>', { value: '', text: 'Choisir une option' }));
for (var i = 0; i < result.length; i++) {
console.log(result[i]);
alert(result[i][0]);
jQuery('#bfLabel410').append(jQuery('<option>', { value: result[i][1], text: result[i][0] }));
} // fin boucle for
} // fin success
} // fin params ajax
); // fin jQuery.ajax()
break;
default: ;
} // fin switch
}
jQuery('#bfLabel410').append(jQuery('<option value="">' + 'Choisir une option' + '</option>' ));
for (var i = 0; i < result.length; i++) {
console.log(result[i]);
alert(result[i][0]);
jQuery('#bfLabel410').append(jQuery('<option value="' + result[i][1] + '">' + result[i][0] + '</option>'));
}
I make a call to a Firebase Firestore database. I push the results into an array.
I output the results to console. However, I am unable to access the data (line 48) in the array even though it is there (line 45) as per image below. What could I be doing wrong?
var collectSnap = new Array()
var collectionRef = db.collection("players").get()
.then(function(querySnapshot) {
querySnapshot.forEach((doc) => {
console.log(doc.id, " => ", doc.data())
var docData = doc.data()
collectSnap.push(docData);
})
return collectSnap
})
.catch(function(error){ console.log("error!", error)})
console.log('collectSnap', collectSnap)
for (var i = 0; i < 4; i++) {
console.log(i + ' : ' + collectSnap[i])
}
You are fetching the data in an asynchronous function call, but trying to access it synchronously (before the server has actually responded).
Try something like this:
function runWhenReady(players) {
for (var i = 0; i < 4; i++) {
console.log(i + ' : ' + players[i])
}
}
db.collection("players").get()
.then(querySnapshot => querySnapshot.docs.map(d => d.data()))
.then(runWhenReady);
I'm trying to get some for Loops running inside a google cloud functions everytime I delete my /users node.
This is the code I'm using
exports.deleteUserAssets = functions.database.ref('/users/{userId}').onWrite((change, context) => {
const beforeData = change.before.val();
const afterData = change.after.val();
const userBuildings = Object.keys(beforeData.isAdmin); // get the buildings of the user stored in the user/userId/isAdmin node .. so far so good
const userId = beforeData.userIDforCloudFunctions; // I'm getting this from a /users/userid/userIDforCloudFucntions node ...so far so good (i've been logging it to confirm)
// making sure it was a delete operation ... so far so good
if (afterData !== null) {
return 0;
}
else {
// on each building
for (var i = 0; i < userBuildings.length; i++) {
let eachBuilding = [userBuildings[i]]
// HERE IS WERE THE PROBLEM IS: Trying to delete all depts + rooms + doors
admin.database().ref('/buildings/' + eachBuilding)
.child("hasDepts")
.once("value")
.then(function(snapshot) { // This is where it goes south – snapshot is returning null
snapshot.forEach(function(childSnapshot) {
var deptKeyString = childSnapshot.key; // will try to get the keys of the departments stored under this space
var deptsOnNode = admin.database().ref('/depts/' + deptKeyString);
deptsOnNode.remove(); // and use the keys to delete each of the depts on depts
});
});
admin.database().ref('/buildings/' + eachBuilding).set({}); // this is working
admin.database().ref('/buildingsUserUid/' + userId + '/' + eachBuilding).remove(); // this is working
}
}
return 0;
});
The snapshot of admin.database().ref('/buildings/' + eachBuilding).child("hasDepts") is returning null.
How can I get to it? Besides admin.database().ref() I've tried to reach it with firebase.database().ref() which is the command/object i use to get this running on frontend functions. I've also tried functions.database() with no result.
Taking in consideration what Doug Stevenson mentioned in his second comment:
exports.deleteUserAssets = functions.database.ref('/users/{userId}').onDelete((change, context, event) => {
const beforeData = change.before.val(); // data before the write (data of all the doors child nodes)
const afterData = change.after.val(); // data before the write (data of all the doors child nodes)
const userBuildings = Object.keys(beforeData.isAdmin); // get the buildings of the user
const userId = beforeData.userIDforCloudFunctions;
// make sure user was deleted
if (afterData !== null) {
return 0;
}
else {
// on each building
for (var i = 0; i < userBuildings.length; i++) {
let eachBuilding = [userBuildings[i]]
// Need to RETURN the whole chain of promises
return admin.database().ref('/buildings/' + eachBuilding)
.child("hasDepts")
.once("value")
.then(function(snapshot) {
console.log(snapshot.val()) // this now works
snapshot.forEach(function(childSnapshot) {
console.log(childSnapshot.val()) // this works as well
var deptKeyString = childSnapshot.key; // get the keys of the departments stored under this space
var deptsOnNode = admin.database().ref('/depts/' + deptKeyString);
// and you can keep on going deeper if you return promises
return deptsOnNode
.child('hasRooms')
.once('value')
.then(function(grandchildSnapshot){
console.log(grandchildSnapshot.val())
grandchildSnapshot.forEach(function(grandGrandchildSnapshot){
var roomKeyString = grandGrandchildSnapshot.key;
var roomsOnDepts = admin.database().ref('/rooms/' + roomKeyString);
admin.database().ref('/roomOwners/' + userId + '/' + roomKeyString).remove();
// and return again here...
return roomsOnDepts
.child('hasDoors')
.once('value')
.then(function(grandgrandGrandchildSnapshot){
grandgrandGrandchildSnapshot.forEach(function(grandgrandGrandchildSnapshot){
var doorKeyString = grandgrandGrandchildSnapshot.key;
var doorsOnRooms = admin.database().ref('/doors/' + doorKeyString);
doorsOnRooms.remove();
let clipOwners = admin.database().ref('/clipOwners/' + doorKeyString);
clipOwners.remove();
})
roomsOnDepts.remove();
})
})
deptsOnNode.remove(); // use the keys to delete the depts on depts main Node
})
});
admin.database().ref('/buildings/' + eachBuilding).set({});
admin.database().ref('/buildingsUserUid/' + userId + '/' + eachBuilding).remove();
});
}
}
return 0;
});
I'd like to retrieve the name and the date of created tasks. I managed to put the value taskMessage in local storage, but I don't know how to add taskName as well. This is the code I currently have :
$(document).ready(function () {
var i = 0;
for (i = 0; i < localStorage.length; i++) {
var taskID = "task-" + i;
$('.task-container').append("<li class='item-content' id='" + taskID + "'>" + localStorage.getItem(taskID) + "</li>");
}
$('.floating-button').on('click', function () {
myApp.prompt('', 'Add Task', function (task) {
if (task !== "") {
myApp.prompt('', 'Choose time', function (time) {
var d1 = new Date();
d1.setHours(time, 0, 0, 0);
var hour = d1.getHours();
if (time > 0 && time < 25) {
var d2 = new Date();
var currenttime = d2.getHours();
if (time > currenttime) {
var taskID = "task-" + i;
var taskMessage = hour;
var taskName = task;
localStorage.setItem(taskID, taskMessage);
var newtask = '<li class="item-content ' + taskID + '"><div class="item-inner"><div class="item-title" >' + taskName + '</div><div class="item-after"> ' + taskMessage + ':00</div> </div></li>';
var taskitem = $('#' + taskID);
$('.task-container').append(newtask);
}
else {
myApp.addNotification({
message: 'Please choose a valide time period'
});
}
}
else {
myApp.addNotification({
message: 'Please choose a value between 1 and 24'
});
}
});
}
else {
myApp.addNotification({
message: 'Please enter a valid name'
});
}
});
});
});
First you should get the data into a variable
var getData =
{
"firstData":"data1",
"secondData":"data2",
"thirdData": "data3"
}
Then you can set the above data's in localStorage...
localStorage.setItem('dataKey', JSON.stringify(getData ));
Then get....
var val = localStorage.getItem('dataKey');
Enjoy!!!
If you want to store two different values in localStorage then you can do somrthing like this :
setItem in localStorage two times with different keys.
localStorage.setItem("message", taskMessage);
localStorage.setItem("name", taskName);
Store both the values in an object.
var obj = {
"message": taskMessage,
"name": taskName
}
var val = localStorage.setItem("task", obj);
typeof val: string
Value of val: [object Object]
setItem method convert the input to a string before storing it.
Try this :
// Put the object into storage
localStorage.setItem('task', JSON.stringify(obj));
// Retrieve the object from storage
var val = localStorage.getItem('obj');
console.log('retrievedValue: ', JSON.parse(val));
You can easily store values in localstorage using following example.
//Save the values to Localstorage
localStorage.setItem('first','firstvalue');
localStorage.setItem('second','secondvalue');
//Retrieve the values from localstorage
localStorage.getItem('first')
//"firstvalue"
localStorage.getItem('second')
//"secondvalue"
localStorage saves item key&value as string,so you call setItem with an object/json object,you must serialize json to string by JSON.stringify() method.when you get value you need parse string as json object using JSON.parse() method.
Test
test(`can't retrieve json from localStorage if raw json data saved`, () => {
localStorage.setItem('foo', {foo: 'bar'});
expect(localStorage.getItem('foo')).toEqual('[object Object]');
});
test(`retrieve json value as string from localStorage`, () => {
localStorage.setItem('foo', JSON.stringify({foo: 'bar'}));
let json = JSON.parse(localStorage.getItem('foo'));
expect(json.foo).toEqual('bar');
});
test(`key also be serialized`, () => {
localStorage.setItem({foo: 'bar'}, 'value');
expect(localStorage.getItem('[object Object]')).toEqual('value');
});
test('supports bracket access notation `[]`', () => {
localStorage.setItem('foo', 'bar');
expect(localStorage['foo']).toEqual('bar');
});
test('supports dot accessor notation `.`', () => {
localStorage.setItem('foo', 'bar');
expect(localStorage.foo).toEqual('bar');
});
I write some simple app for windows 8 Metro UI with javascript. Because natural method from microsoft to use Sqlite with Javascript in Metro UI. I use 'doo' wrapper:
dooWrapper SQLite (github)
I create a method :
function addSomething(name) {
var dbPath = Windows.Storage.ApplicationData.current.localFolder.path + '\\a_db.sqlite';
SQLite3JS.openAsync(dbPath).then(function (db) {
return db.runAsync("INSERT INTO STH (nazwa) VALUES (:name)", { name: name }).
done(function () {
console.log('Add sth : ' + name);
db.close();
}, function (error) {
if (db) {
db.close();
}
console.log('ERROR Adding sth' + error.message);
})
});
}
I get error 'database is locked' I read about this error in documentation. But I have one question is other solution to add more rows without create 'insert' function with collections argument something like that : insert (array) ? I just want to use that function n-times without this error. That's possible?
Yes,it possible...i also got this error before....For that you just need to establish the database connection once...i have used this in my app and its working fine.
If there is no need of closing your db then then open database once like..
Add this code to default.js file
var myDatabase; //Global Variable
var dbPath = Windows.Storage.ApplicationData.current.localFolder.path + '\\db.sqlite';
//Create Table
SQLite3JS.openAsync(dbPath).then(function(db) {
myDatabase=db;
return db.runAsync('CREATE TABLE Item (name TEXT, price REAL, id INT PRIMARY KEY)');
});
Then you just need to use below code
// For Insert
return myDatabase.runAsync('INSERT INTO Item (name, price, id) VALUES ("'+ array[i].name+'", "48484", 1);
For array
var dbPromises = [];
var testArray = [];
//only for test purpose
//You can pass your array here directly
for (var a = 0; a < 300; a++) {
var obj = {
name: "Mango"+a,
price: 100+a,
id: a
};
testArray.push(obj);
}
for (var i = 0; i < testArray.length; i++) {
var query = 'INSERT OR REPLACE INTO Item (name, price, id) VALUES ("' + testArray[i].name + '",' + testArray[i].price + ',' + testArray[i].id + ')';
dbPromises.push(globalDatabase.allAsync(query));
}
WinJS.Promise.join(dbPromises).then(function () {
debugger;
}, function(err) {
debugger;
});
Above code is used only for less array size...bcz its taking too much time for insertion...
For fasst execution you should replace just below code
for (var i = 0; i < testArray.length; i++) {
var val = '("' + testArray[i].name + '",' + testArray[i].price + ',' + testArray[i].id + '),';
query = query + val;
if ((i + 1) % 300 == 0 || (i + 1) == testArray.length) {
query = query.replace(/,$/, "");
dbPromises.push(globalDatabase.allAsync(query));
query = 'INSERT OR REPLACE INTO Item (name, price, id) VALUES ';
}
}