AutoIncrement of Multiple columns in indexeddb - auto-increment

Does any one know - how we can specify autoincrement for two columns in indexeddb.
I know - we can specify autoincremnt for one column while creating table like this -
var objectStore = thisDb.createObjectStore("note", { keyPath: "id", autoIncrement:true });
but not able to find how we can do the same for multiple columns. Also as far as i know - we cant get the value of autoincrement. The value will be autoincremented & added when we will insert the data. So if i can get the autoincrement value somehow, that would the solution too.

You cannot create two auto-incremented properties in a store. That feature is only available for the property defined as the key path.
You can easily get the auto-incremented value. The value is provided as the result of the put or add request that inserted a new object.
For example:
function addThing(db, thing) {
return new Promise((resolve, reject) => {
let id = undefined;
const transaction = db.transaction('things', 'readwrite');
const store = transaction.objectStore('things');
// wait to resolve the promise until the transaction is completed
// so that we do not prematurely pretend the operation succeeded. resolve
// to the value of the new id
transaction.oncomplete = event => resolve(id);
transaction.onerror = event => reject(event.target.error);
// store.add also works here
const request = store.put(thing);
// listen for the add event and grab the value of the new id
// that indexedDB generated and store it in the id variable
request.onsuccess = event => id = event.target.result;
});
}
async function doSomething() {
const something = {bar: 'baz'};
const db = await open(...);
const id = await addThing(db, something);
db.close();
something.id = id;
console.log(something);
}

Related

Error: Value for argument "documentPath" is not a valid resource path. Path must be a non-empty string. /*what is empty or not a string*/

this is the error that I get. I checked multiple times that the paths that I indicate are actually pointing at something in the database. I'm kinda going crazy about why this is not working, so help will be appreciated. (the same error is given by both functions, two times every invocation of the function)
this is my code:
exports.onCreatePost = functions.firestore
.document('/time/{userid}/date/{postId}')
.onCreate (async (snapshot, context) => {
const postCreated = snapshot.data();
const userID = context.params.userid;
const postID = context.params.postId;
//get all the followers who made the post
const userFollowerRef = admin.firestore().collection('time').doc(userID).collection('followers');
const querySnap = await userFollowerRef.get();
//add the post in each follower timeline
querySnap.forEach(doc => {
const followerid = doc.id;
admin.firestore().collection('time').doc(followerid).collection('timelinePosts').doc(postID).set(postCreated);
})
});
//when a post is updated
exports.onUpdatePost = functions.firestore
.document('/time/{userid}/date/{postid}')
.onUpdate(async (change, context) => {
const postUpdated = change.after.data();
const userID = context.params.userid;
const postID = context.params.postId;
//get all the followers who made the post
const userFollowerRef = admin.firestore().collection('time').doc(userID).collection('followers');
const querySnap = await userFollowerRef.get();
//Update the post in each follower timeline
querySnap.forEach(doc => {
const follower = doc.id;
admin.firestore().collection('time').doc(follower).collection('timelinePosts').doc(postID)
.get().then(doc => {
if (doc.exists) {
doc.ref.update(postUpdated);
}
});
});
});
I personally don't know how to log each variable and did not find how to do it online. I'll keep searching but in the mindtime I can share my extensive logs that from my interpretation are not very useful but maybe is just because I'm inexperienced.
this is the error log
enter image description here
In function exports.onUpdatePost ...you're likely trying to access documentPath null (or something alike that). Add logging, this permits to log custom debug information into the log which you've screenshotted. When logging every step of the procedure, it's a whole lot easier to determine what is happening and why - or why not, when skipping something. Alike this you should be able to solve the issue on your own. My functions logging actually utilizes emojis, because UTF-8 is being supported: ✅❌ (visual indicators make the log more readable).
The cause seems to be one of these instructions:
admin.firestore().collection('time') // it is being assumed that it exists
.doc(userID) // argument or return value may be null
.collection('followers') // return value may be null
Or:
admin.firestore().collection('time') // it is being assumed that it exists
.doc(follower) // argument or return value may be null
.collection('timelinePosts') // return value may be null
.doc(postID) // argument or return value may be null
eg. one first has to check if follower != null or empty and if the desired document even exists. The same goes for userID and .doc(userID) (the seemingly "own" timeline).
if (follower != null && follower.length > 0) {
admin.firestore().collection('time').doc(follower).get().then(timeline => {
functions.logger.log('timeline: ' follower + ', ' + timeline.exists);
if (timeline.exists) {
} else {
}
});
}
documentPath == null comes from .doc() + userID, followerid, follower or postID.

Firebase Cloud Function Increment Counter

Per Firebase cloud functions docs, "Events are delivered at least once, but a single event may result in multiple function invocations. Avoid depending on exactly-once mechanics, and write idempotent functions."
When looking at a firestore cloud function doc example below of a restaurant rating, they are using an increment counter to calculate the total number of ratings. What are some of the best ways to maintain the accuracy of this counter by using an idempotent function?
Is it reasonable to store the context.eventId in a subcollection document field and only execute the function if the new context.eventId is different?
function addRating(restaurantRef, rating) {
// Create a reference for a new rating, for use inside the transaction
var ratingRef = restaurantRef.collection('ratings').doc();
// In a transaction, add the new rating and update the aggregate totals
return db.runTransaction((transaction) => {
return transaction.get(restaurantRef).then((res) => {
if (!res.exists) {
throw "Document does not exist!";
}
// Compute new number of ratings
var newNumRatings = res.data().numRatings + 1;
// Compute new average rating
var oldRatingTotal = res.data().avgRating * res.data().numRatings;
var newAvgRating = (oldRatingTotal + rating) / newNumRatings;
// Commit to Firestore
transaction.update(restaurantRef, {
numRatings: newNumRatings,
avgRating: newAvgRating
});
transaction.set(ratingRef, { rating: rating });
});
});
}
Is it reasonable to store the context.eventId in a subcollection
document field and only execute the function if the new
context.eventId is different?
Yes, for your use case, using the Cloud Function eventId is the best solution to make you Cloud Function idempotent. I guess you have already watched this Firebase video.
In the Firebase doc from which you have taken the code in your question, you will find at the bottom, the similar code for a Cloud Function. I've adapted this code as follows, in order to check if a doc with ID = eventId exists in a dedicated ratingUpdateIds subcollection:
exports.aggregateRatings = functions.firestore
.document('restaurants/{restId}/ratings/{ratingId}')
.onWrite(async (change, context) => {
try {
// Get value of the newly added rating
const ratingVal = change.after.data().rating;
const ratingUpdateId = context.eventId;
// Get a reference to the restaurant
const restRef = db.collection('restaurants').doc(context.params.restId);
// Get a reference to the ratingUpdateId doc
const ratingUpdateIdRef = restRef.collection("ratingUpdateIds").doc(ratingUpdateId);
// Update aggregations in a transaction
await db.runTransaction(async (transaction) => {
const ratingUpdateIdDoc = await transaction.get(ratingUpdateIdRef);
if (ratingUpdateIdDoc.exists) {
// The CF is retried
throw "The CF is being retried";
}
const restDoc = await transaction.get(restRef);
// Compute new number of ratings
const newNumRatings = restDoc.data().numRatings + 1;
// Compute new average rating
const oldRatingTotal = restDoc.data().avgRating * restDoc.data().numRatings;
const newAvgRating = (oldRatingTotal + ratingVal) / newNumRatings;
// Update restaurant info and set ratingUpdateIdDoc
transaction
.update(restRef, {
avgRating: newAvgRating,
numRatings: newNumRatings
})
.set(ratingUpdateIdRef, { ratingUpdateId })
});
return null;
} catch (error) {
console.log(error);
return null;
}
});
PS: I made the assumption that the Cloud Function eventId can be used as a Firestore document ID. I didn't find any doc or info stating the opposite. In case using the eventId as an ID would be a problem, since you execute the transaction in a Cloud Function (and therefore use the Admin SDK), you could query the document based on a field value (where you store the eventId) instead of getting it through a Reference based on its ID.

How to retrieve a child Entity from a cloud datastore without passing a parent key in nodejs

I have a 2 kinds of entity;
Parent
Child
In the above kinds of entity, a Child is associated with a parent key.
I need to filter for a child based only on a child key as I dont have the parent key, only the child key/id.
const query = datastore.createQuery('Child')
.filter('__key__', '=', datastore.key(['Child', 123]))
The strange thing is, if I pass a ">" operator it will return records, however I need an exact key match, as well as an explanation.
If I have to add a composite index, how would I do so for the above relation?
How are you assigning the child entity key ids? If it is using the allocate id api, then that API doesn't guarantee uniqueness across child entities belonging to different parent entities. As a result, even with a separate index, you can't uniquely query for the child.
One approach is to allocate ids for a top level entity and then use that id as a property on your child entity. Then you can query using that property and get a unique child associated with it.
as you can see here you can doi it like this, by adding the limit(1) you make sure of not getting multiple results.
const Datastore = require('#google-cloud/datastore');
const datastore = new Datastore({
projectId: 'cf-datastore',
keyFilename: 'datastore-credential.json'
});
const kindName = 'user-log';
async getlog = (req, res) => {
let uid = req.query.uid || req.body.uid || 0;
//let log = req.query.log || req.body.log || '';
const key = datastore.key(['uid','log']);
datastore
.get(key,(err, entity) => {});
const query = datastore.createQuery('uid');
query.filter('uid', uid);
query.limit(1);
const transaction = datastore.transaction();
console.log("Transaction");
console.log(transaction);
const results = datastore.runQuery(query, (err, entities) => {
// entities = An array of records.
// Access the Key object for an entity.
firstEntityKey = entities;
console.log("Entities")
console.log(entities);
});
console.log("GOT IT");
console.log("Results")
console.log(results);
//console.log("Entity");
//console.log(entity);
const task = await datastore.runQuery(query);
console.log(task);
//second part
res.status(200).send(results);
};
exports.executed = (req, res){
console.log(` CALLING`);
getlog(req, res)
setTimeout(() => {
resolve('resolved');
}, 20000);
}

Firebase unique id to query my data to get a value from the child

I am trying to use the unique id that firebase gives to get the data value from the child. I can get the data value from the child by hardcoding the unique id. But the database will have multiples stored and I want to get newest stored data.
I have tried to use the pushId but it makes the child come back null
function handler(agent){
const db = firebase.database();
// const numberParam = agent.parameters.checknumber;
const ref = db.ref('/cnumber/transaction/{pushId}/');
return ref.once('value')
.then((datashot) =>{
const number = datashot.child('cnumber').val();
agent.add('The number is' + number);
console.log(number);
});
}
If you're trying to retrieve the latest child node:
function handler(agent){
const db = firebase.database();
const ref = db.ref('/cnumber/transaction');
return ref.orderByKey().limitToLast(1).once('child_added').then((datashot) =>{
const number = datashot.child('cnumber').val();
agent.add('The number is' + number);
return number;
});
}

Get unique Key from Firebase Database

I am writing to the RealTime Database using a db file. The field generates a unique id key and I need to pass that key back to the parent file.
My db function:
export const doCreateCompany = name =>
db
.ref(`company`)
.push()
.set({ name });
My calling function is as follows:
db.doCreateCompany(companyName).then((e) => {
console.log("Key", e);
I need to write another function immediately following using the unique key. Any help is great. Thanks
If you want your function to still return a promise that resolves when the set() is complete, and also have access to the push ID, try something like this:
export const doCreateCompany = name => {
const ref = db.ref('company').push()
return ref.set({ name }).then(() => {
return Promise.resolve(ref.key)
})
}
Then you can call it like this:
doCreateCompany(name).then(key => {
// key is the push id here
})
You can separate the call to push() from the set(...):
export const doCreateCompany = name =>
var ref = db.ref(`company`).push();
var key = ref.key;
ref.set({ name });
Now you can return the key to whoever called the function.

Resources