"documentRef" is not a valid DocumentReference showing while updating a field - javascript

I'm trying to count the number of notification. My database structure is Users/userId/notification/doc. I want to keep track number of the notification. My code is
notificationCount: async (change,context) => {
const countRef=db.collection("Users").doc(context.params.userID);
let increment;
if (change.after.exists && !change.before.exists) {
increment = 1;
} else if (!change.after.exists && change.before.exists) {
increment = -1;
} else {
return null;
}
return db.runTransaction((transaction) => {
return transaction.get(countRef).then((sfDoc) => {
if (!sfDoc.exists) {
return transaction.set({
notifications: 0
}, { merge: true });
} else {
var newNotification = sfDoc.data().population + increment;
return transaction.set({
notifications: newNotification
});
}
});
}).then(() => {
console.log("Transaction successfully committed!");
return null;
}).catch((error) => {
console.log("Transaction failed: ", error);
});
}
But I'm getting error
at Object.validateDocumentReference (/srv/node_modules/#google-cloud/firestore/build/src/reference.js:1810:15)
at WriteBatch.set (/srv/node_modules/#google-cloud/firestore/build/src/write-batch.js:241:21)
at Transaction.set (/srv/node_modules/#google-cloud/firestore/build/src/transaction.js:182:26)
at transaction.get.then (/srv/counter.js:71:30)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:229:7)

Your error is in two places:
return transaction.set({
notifications: 0
}, { merge: true });
And here:
return transaction.set({
notifications: newNotification
});
You have to call out a specific document to update when calling transaction.set(). As you can see from the linked API docs, the first argument to set() must be a DocumentReference type object, but you're passing a plain old JavaScript object. Perhaps you meant to use the document reference countRef that you used to read from the same transaction:
return transaction.set(countRef, {
notifications: newNotification
});

Related

Chrome Extension: How to get object from DB when searching by value?

Im trying to create a chrome extension, and have encountered an annoying problem. I have this function, where I add an object to my indexedDB if the urlKeyValue of that object, does not already exist in the database.
If the urlKeyValue does exist in the DB, i want to get the object in the DB that contains that value. This is where my problem begins. On line 184 - 188, i try to get the object by searching by the `urlKeyValue, but when I try to print the object, i get undefined.
Question: How to get an object from IndexedDB by a value?
This is how my objects are structured:
{
message: "insert",
payload: [
{
urlKeyValue: "",
url: {
[userId]: {
[time]: {
msg: form_data.get("message"),
},
},
},
},
],
}
My Function where it all happens:
function insert_records(records, when) {
if (db) {
const insert_transaction = db.transaction(["roster2"], "readwrite");
const objectStore = insert_transaction.objectStore("roster2");
return new Promise((resolve, reject) => {
insert_transaction.oncomplete = function () {
console.log("ALL INSERT TRANSACTIONS COMPLETE.");
resolve(true);
};
insert_transaction.onerror = function () {
console.log("PROBLEM INSERTING RECORDS.");
resolve(false);
};
records.forEach((person) => {
// the "when" varieable isnt important, just disregard it
if (when != "init") {
const index = objectStore.index("urlKeyValue");
let search = index.get(person.urlKeyValue);
search.onsuccess = function (event) {
if (search.result === undefined) {
// no record with that key
let request = objectStore.add(person);
request.onsuccess = function () {
console.log("Added: ", person);
};
}
else {
const request2 = objectStore.get(person.urlKeyValue);
request2.onsuccess = function (event) {
console.log("--------" + event.target.result);
};
}
};
} else {
// this else statement isnt really important for this question
let request = objectStore.add(person);
request.onsuccess = function () {
console.log("Added: ", person);
//self.location.href;
};
}
});
});
}
}
EDIT:
This is an example of an object I store:
let roster = [
{
urlKeyValue: "https://www.youtube.com/",
"https://www.youtube.com/": {
1: {
20: {
msg: "this is some init data",
},
},
},
},
];

ERROR TypeError: subscribe is not a function in Ionic 4

I am doing with Ionic News App. I have one problem with getting a response from the service file.
home.page.ts
getNews(): void {
this.loading = true;
this.language = localStorage.language;
this.checkForToken();
var userId = this.loggedInUser;
this._newsService.getAllNews().subscribe(
(res: any) => {
console.log("all news==========>", res)
this.loadNewsToPage(res, userId);
},
(err) => {
this.loading = false;
this.error = err;
});
}
news.service.ts
getAllNews(){
if(this.network.type == 'none' ){
console.log(JSON.parse(localStorage.getItem("newsArray")));
this.newsArray = JSON.parse(localStorage.getItem("newsArray"))
return this.newsArray;
}else{
return this.http.get(config.baseApiUrl + 'news?isApproved=APPROVED').pipe(
map((res) => {
this.newsArray = res['data'];
localStorage.setItem('newsArray',JSON.stringify(this.newsArray))
return this.newsArray;
}),
catchError(this.handleError));
}
}
Now the problem is when the network is 'none' it goes in 'if' condition in service file and return response from local storage. But it gives me below error when network is none.
ERROR TypeError: this._newsService.getAllNews(...).subscribe is not a
function
It works properly when it goes in else condition or when a network is present. Why like this?
Your getAllNews function isn't an Observable. So you can't subscribe to it. See the example below where you return an Observable for the first if condition and the second else condition. You need to close the Observable with observer.complete() after each next function.
getAllNews(): Observable<any>{
return new Observable(observer => {
if(this.network.type == 'none' ){
console.log(JSON.parse(localStorage.getItem("newsArray")));
this.newsArray = JSON.parse(localStorage.getItem("newsArray"))
observer.next(this.newsArray);
observer.complete();
} else{
this.http.get(config.baseApiUrl + 'news?isApproved=APPROVED').subscribe(
(result: object) => {
this.newsArray = result['data'];
localStorage.setItem('newsArray',JSON.stringify(this.newsArray))
observer.next(this.newsArray);
observer.complete();
},
(error) => {
observer.error(error);
});
}
});
}
You can now access the next block in your subscribe > result and the error block in subscribing> error.
this._newsService.getAllNews().subscribe(
(res: any) => { // observer.next() brings you here
console.log("all news==========>", res)
this.loadNewsToPage(res, userId);
},
(err) => { // observer.error() brings you here
this.loading = false;
this.error = err;
});

Conditionally execute branch if variable is not undefined

I have a piece of code and a variable sometimes comes as undefined but I need to validate if that value is undefined to pass the execution of code
the validation I provided is not solving the problem
_getKeycodeScans = (data) => this.props.getKeycodeScans(data.keycode.uid, 1).then(() => {
this.setState({detailsModalVisible: true, homeDetails: data});
}).catch(error => {
debugger
const { serverError } = JSON.parse(error.message);
this.setState({ serverError, loading: false });
});
_openDetailsModal = (data) => () => Promise.all([
console.log('&&&&&&&&&&&&&&&&&&&&**********&&&&&&&&&&&&&&&&&&&&&'),
console.log(data),
this._getKeycodeScans(data),
this._getKeycodeImageDataUrl(data),
this._getHomes(data)
]);
When the _openDetailsModal gets hit and it calls the functions inside and the uid is undefined.
I get the error message: TypeError: Cannot read property 'uid' of undefined.
When uid is undefined I actually don't need the data
If your goal is to only continue executing your script if data.keycode.uid is not undefined, you could just:
_getKeycodeScans = (data) => {
if(!data.keycode || data.keycode.uid === undefined) {
return;
}
return this.props.getKeycodeScans(data.keycode.uid, 1).then(() => {
this.setState({detailsModalVisible: true, homeDetails: data});
}).catch(error => {
const { serverError } = JSON.parse(error.message);
this.setState({ serverError, loading: false });
});
}

Promise resolution

I am new to javascript promises, I am using below code from NativeScript to query sqlite database and just want to return true if row exists and false otherwise:
function hasBookmark(url) {
(new Sqlite("pakjobs.db")).then(db => {
db.all("SELECT url FROM bookmarks WHERE url=?", [url]).then(rows => {
return rows.length ? true : false;
}, error => {
console.log("hasBookmark ERROR", error);
return false;
});
}, error => {
console.log("hasBookmark ERROR", error);
return false;
});
return false;
}
However function ALWAYS returns false.
Can anybody tell how do I return true if row exists and false otherwise ?
Thanks for the help
You are not going to be able to return true or false, that's pretty much the point of Promises, you can't return something asynchronously in javascript.
What you can do, however, is directly returning the Promise you're creating and then calling .then on it.
function hasBookmark(url) {
return (new Sqlite("pakjobs.db")).then(db => {
return db.all("SELECT url FROM bookmarks WHERE url=?", [url]).then(rows => {
return rows.length ? true : false;
}, error => {
console.log("hasBookmark ERROR", error);
return false;
});
}, error => {
console.log("hasBookmark ERROR", error);
return false;
});
}
const hasBookmarkPromise = hasBookmark('someurl');
hasBookmarPromise.then(value => {
if (value === true) {
console.log('has bookmarks');
}
});
function hasBookmark(url) {
return new Promise((resolve, reject) => {
(new Sqlite("pakjobs.db")).then(db => {
db.all("SELECT url FROM bookmarks WHERE url=?", [url]).then(rows => {
resolve(rows.length ? true : false)
}, error => {
console.log("hasBookmark ERROR", error);
resolve(false);
});
}, error => {
console.log("hasBookmark ERROR", error);
resolve(false);
});
});
}
hasBookmark(url).then(function(isValid){
If(isValid){
// Do something
}
});

Firebase's set() not working inside onAuthStateChanged()

I'm currently developing my first "big" web app with ReactJS using Firebase as my DB. Everything was going well until I came across with this issue.
I'm trying to save the user info when they log in into the app with Facebook or Twitter, I'm using the methods provided by Firebase like this:
authenticate(option){
let provider;
switch (option) {
case 'facebook':
provider = new firebase.auth.FacebookAuthProvider();
break;
case 'twitter':
provider = new firebase.auth.TwitterAuthProvider();
break;
default:
provider = 'no-provider'
break;
}
if(provider !== 'no-provider'){
firebase.auth().signInWithPopup(provider).then((result) => {
console.log("Login with " + provider + " ok!");
console.log(result);
}).catch((error) => {
console.log("Error: there was an error trying to login.");
});
}
}
But when I try to save the user into the DB once they've logged in, nothing happens.
This is what I have on App.js
componentDidMount() {
base.auth().onAuthStateChanged((loggedUser) => {
if (loggedUser) {
this.setState({
userName: loggedUser.displayName,
userPhoto: loggedUser.photoURL,
userUID: loggedUser.uid
});
base.database().ref('users/' + loggedUser.uid).on('value',
(user) => {
if (user.val() !== null) {
if (user.val().votedAlbums !== undefined) {
this.setState({
votedAlbums: user.val().votedAlbums
});
}
} else {
console.log(loggedUser.uid);
let userInfo = {
lastActivityTime: new Date()
}
base.database().ref('users/' + loggedUser.uid).set(userInfo).then((ref) =>{
console.log(ref); // this logs 'undefined'
}).catch((error) => {
console.log(error);
});
}
},
(err) => {
this.props.history.push('/error');
}
);
}
});
}
I tried saving the user on another function and it works, both update() and set(). But when I call set() inside onAuthStateChanged() it doesn't.
My DB rules are:
{
"rules": {
".read": true,
".write": "auth != null"
}
}
Am I missing something?
Thanks
As #bennygenel suggested, I changed the value of lastActivityTime to a simple string like this:
componentDidMount() {
base.auth().onAuthStateChanged((loggedUser) => {
if (loggedUser) {
this.setState({
userName: loggedUser.displayName,
userPhoto: loggedUser.photoURL,
userUID: loggedUser.uid
});
base.database().ref('users/' + loggedUser.uid).once('value',
(user) => {
if (user.val() !== null) {
if (user.val().votedAlbums !== undefined) {
this.setState({
votedAlbums: user.val().votedAlbums
});
}
} else {
console.log(loggedUser.uid);
let userInfo = {
lastActivityTime: "whatever" // replaced new Date() with "whatever"
}
base.database().ref('users/' + loggedUser.uid).set(userInfo).then((ref) =>{
console.log(ref);
}).catch((error) => {
console.log(error);
});
}
},
(err) => {
this.props.history.push('/error');
}
);
}
});
}
And now when the user logs in its added to the DB. I also changed the on() method with once() because it was adding the user even if I deleted directly from the Firebase console.
Now to add the date to lastActivityItem I only have to add the toString() method to the generated date like this:
let d = new Date()
let userInfo = {
lastActivityTime: d.toString()
}
If someone knows why this happened, please share.
Thank you #bennygenel !!!

Categories