"_id":{"$id":"61b5eb36029b48135465e766"},
"name":"push-ups","link":"https://google.com",
"image":"https://google.com",
"gender":["0","1","2"],
"goal":["lw","gw","sf"],
"age":60,
"excersietype":"chest",
"__v":0
this is how my data is stored in database
and I want to fetch data according to 3 condition
I got 3 queries from front gender goal and age and according to that I have to retrieve data
const gender = req.query.gender;
const age = req.query.age;
const goal = req.query.goal
const level = req.query.level
if (level==='fb'){
const getdata = new Forbeg.find({gender:{$in:gender}},{age:{$lte:age}},{goal:{$in:goal}});
console.log(getdata)
}
Is this a good way to find the data because I am getting error
UnhandledPromiseRejectionWarning: MongooseError: `Model.find()` cannot run without a model as `this`. Make sure you are not calling `new Model.find()`
I am getting above error while fetching
The error is explicit : Make sure you are not calling 'new Model.find()'. Use const getdata = Forbeg.find(...).
However, you will immediately run into the next problem, as Mongoose models return thenables (Promise-like). console.log(getdata) will log Promise<pending>. You need to resolve your database call, either by doing
Forbeg.find(...).then( getdata => console.log(getData));
or (much more better!):
const getdata = await Forbeg.find(...);
console.log(getdata)
Even better, add .lean() to get simple JSON data instead of an array of Mongoose objects (faster), and .exec() to get a true Promise instead of a thenable :
const getdata = await Forbeg.find(...).lean().exec();
console.log(getdata)
Remove new operator
const getData = Forbeg.find({gender:{$in:gender}},{age:{$lte:age}},{goal:{$in:goal}});
Related
I'm using Firebase as backend to my iOS app and can't figure out how to construct a batch write through their Cloud Functions.
I have two collections in my Firestore, drinks and customers. Each new drink and each new customer is assigned a userId property that corresponds to the uid of the currently logged in user. This userId is used with a query to the Firestore to fetch only the drinks and customers connected to the logged in user, like so: Firestore.firestore().collection("customers").whereField("userId", isEqualTo: Auth.auth().currentUser.uid)
Users are able to log in anonymously and also subscribe while anonymous. The problem is if they log out there's no way to log back in to the same anonymous uid. The uid is also stored as an appUserID with the RevenueCat SDK so I can still access it, but since I can't log the user back in to their anonymous account using the uid the only way to help a user access their data in case of a restoring of purchases is to update the userId field of their data from the old uid to the new uid. This is where the need for a batch write comes in.
I'm relatively new to programming in general but I'm super fresh when it comes to Cloud Functions, JavaScript and Node.js. I dove around the web though and thought I found a solution where I make a callable Cloud Function and send both old and new userID with the data object, query the collections for documents with the old userID and update their userId fields to the new. Unfortunately it's not working and I can't figure out why.
Here's what my code looks like:
// Cloud Function
exports.transferData = functions.https.onCall((data, context) => {
const firestore = admin.firestore();
const customerQuery = firestore.collection('customers').where('userId', '==', `${data.oldUser}`);
const drinkQuery = firestore.collection('drinks').where('userId', '==', `${data.oldUser}`);
const customerSnapshot = customerQuery.get();
const drinkSnapshot = drinkQuery.get();
const batch = firestore.batch();
for (const documentSnapshot of customerSnapshot.docs) {
batch.update(documentSnapshot.ref, { 'userId': `${data.newUser}` });
};
for (const documentSnapshot of drinkSnapshot.docs) {
batch.update(documentSnapshot.ref, { 'userId': `${data.newUser}` });
};
return batch.commit();
});
// Call from app
func transferData(from oldUser: String, to newUser: String) {
let functions = Functions.functions()
functions.httpsCallable("transferData").call(["oldUser": oldUser, "newUser": newUser]) { _, error in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
let details = error.userInfo[FunctionsErrorDetailsKey]
print(code)
print(message)
print(details)
}
}
}
}
This is the error message from the Cloud Functions log:
Unhandled error TypeError: customerSnapshot.docs is not iterable
at /workspace/index.js:22:51
at fixedLen (/workspace/node_modules/firebase-functions/lib/providers/https.js:66:41)
at /workspace/node_modules/firebase-functions/lib/common/providers/https.js:385:32
at processTicksAndRejections (internal/process/task_queues.js:95:5)
From what I understand customerSnapshot is something called a Promise which I'm guessing is why I can't iterate over it. By now I'm in way too deep for my sparse knowledge and don't know how to handle these Promises returned by the queries.
I guess I could just force users to create a login before they subscribe but that feels like a cowards way out now that I've come this far. I'd rather have both options available and make a decision instead of going down a forced path. Plus, I'll learn some more JavaScript if I figure this out!
Any and all help is greatly appreciated!
EDIT:
Solution:
// Cloud Function
exports.transferData = functions.https.onCall(async(data, context) => {
const firestore = admin.firestore();
const customerQuery = firestore.collection('customers').where('userId', '==', `${data.oldUser}`);
const drinkQuery = firestore.collection('drinks').where('userId', '==', `${data.oldUser}`);
const customerSnapshot = await customerQuery.get();
const drinkSnapshot = await drinkQuery.get();
const batch = firestore.batch();
for (const documentSnapshot of customerSnapshot.docs.concat(drinkSnapshot.docs)) {
batch.update(documentSnapshot.ref, { 'userId': `${data.newUser}` });
};
return batch.commit();
});
As you already guessed, the call customerQuery.get() returns a promise.
In order to understand what you need, you should first get familiar with the concept of promises here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
For your use case, you will probably end up with either using the then callback:
customerQuery.get().then((result) => {
// now you can access the result
}
or by making the method call synchronous, by using the await statement:
const result = await customerQuery.get()
// now you can access the result
const signupTime =admin.database.ServerValue.TIMESTAMP
database.ref(`/admin/vendorOrder/${vendor}/${userID}`).set(signupTime);
console.log(signupTime);
i want the time value
while in database it returns correctly
in consol log it returns
how do i make it return value in string
also
database.ref(`/admin/vendorOrder/${vendor}/${userID}/${signupTime}/order`).set(order);
returns error
kindly help
As explained in the doc, with ServerValue.TIMESTAMP you get "a placeholder value for auto-populating the current timestamp as determined by the Firebase servers".
In other words signupTime does not contain the value of the timestamp, since this one is set on the server (the back-end) when you write to the database.
If you want to get this value in your Cloud Function (or in a front-end), you need to query the newly set database node, as follows, for example:
const signupTime = admin.database.ServerValue.TIMESTAMP
const database = admin.database();
const ref = database.ref(`/admin/vendorOrder/${vendor}/${userID}`);
ref
.set(signupTime)
.then(() => {
return ref.get();
})
.then((snap) => {
console.log(snap.val());
})
.catch((error) => {
console.log(error);
});
I'm new to Javascript and react native, and the question itself will be probably very easy to answer.
I'm setting up a AsyncStorage and creating a Item inside the storage, which is a .JSON that has 3 key values to it.
const saveDataToStorage = (token, userId, expirationDate) => {
AsyncStorage.setItem('userData', JSON.stringify({
token: token,
userId: userId,
expiryDate: expirationDate.toISOString()
}))
};
What I want to do now is to retrieve the "userId" value from this item in an other part of the project but here is the problem.
var PersonalId = await AsyncStorage.getItem('userData');
console.log(PersonalId);
console.log(typeof PersonalId);
I know how to access the item itself, but I have no clue how to access the special key inside it. I can not use the command:
var PersonalId = await AsyncStorage.getItem('userData').userId;
because the item from the AsyncStorage is a string, I know this because I got this info from the second line of my code.
console.log(typeof PersonalId);
How can I access the special key "userId" inside my item "userData" and not the whole item itself? I cant work with the item anyways because its a string, I can not treat it as an object and thats my problem.
Thank you for reading and helping out!
You need to first parse value you are getting from the AsyncStorage into a JSON object using JSON.parse(). Try this implementation.
const get_data = async () => {
const userData = await AsyncStorage.getItem("userData");
const userObject = userData !== null ? JSON.parse(userData) : {};
const personalId = userObject.userId;
console.log(personalId);
};
You are forgetting that you stringified the JSON before saving it to storage.. so you are getting string when you read it. Simply JSON.parse the returned string and you should be on your way.
const userData = await AsyncStorage.getItem('userData');
const personalId = JSON.parse(userData).userId;
You should also wrap the above code in a try-catch to make sure you catch errors when invalid data is tried to be parsed and it throws an error.
I am using AsyncStorage to store data. Here is my function of storing data :
const profile = { userId, name, email };
await AsyncStorage.setItem('userProf', JSON.stringify(profile));
I have a problem when I try to access the data , if I console.log:
async componentWillMount(){
const profile = await AsyncStorage.getItem('userProf');
console.log(profile);
}
{"userId":"jefla3E0tjcJHhHKJK45QoIinB2","name":"egfgege","email":"ergeg#egrge.com"}
Now if I am willing to get only email value , I have tried with:
console.log(profile.email);
console.log(profile[0].email);
None of them worked, I get undefined as output, could you please help.
As AsyncStorage take and returns a string you will need to parse the string into json. You're already using JSON.stringify to save your object, you need to do the reverse operation to get it back to being an object.
const savedProfile = await AsyncStorage.getItem('userProf');
const profile = JSON.parse(savedProfile);
Then you should be able to access it the properties as you normally would, for example
const userId = profile.userId;
const email = profile.email;
const name = profile.name;
You may want to make sure that you perform a check that the returned value from AsyncStorage isn't null, as that will cause problems for you. Also await functions can throw, so you should make sure that you wrap your call to AsyncStorage in a try/catch
async componentWillMount(){
try {
const savedProfile = await AsyncStorage.getItem('userProf');
// you should check that the savedProfile is not null here
const profile = JSON.parse(savedProfile);
const userId = profile.userId;
const email = profile.email;
const name = profile.name;
} catch (err) {
console.warn(err);
}
console.log(profile);
}
When storing the value with AsyncStorage.setItem( ... ), you use JSON.stringify to convert the complete object into a String. This means, if you want to have a "normal" Object back (to use the dot operator), you have to use JSON.parse:
const profile = await AsyncStorage.getItem('userProf');
console.log(JSON.parse(profile));
I am using firebase functions and have successfully run a sanitize function.
The problem I am having is my firebase database looks like this.
The ABC123 and the 0l692lPD6EfqUZ4Y4xiCOVmnNmC2 are both sets automatically when a post is created so I would not know what they will be.
I can hard code the first ABC123 and set {postID} for the second one and it runs successfully. But if I set both to posteId it fails.
below is my code. I need to be able to change the ABC123 to postId because I will not know what it will be in my index.js code.
exports.sanitizePost = functions.database
.ref('/posts/ABC123/question/{postId}')
.onWrite(event => {
const post = event.data.val()
if (post.sanitized) {
return
}
console.log("Sanitizing new post " + event.params.pushId)
console.log(post)
post.sanitized = true
post.question = sanitize(post.question)
const promise = event.data.ref.set(post)
return promise
})
function sanitize(s) {
var sanitizedText = s
sanitizedText = sanitizedText.replace(/\bstupid\b/ig, "wonderful")
return sanitizedText
}
I need .ref('/posts/ABC123/question/{postId}') to be .ref('/posts/{postID}/question/{postId}') or somthing that works.
You cannot have the same parameter twice in a path. But you can have two parameters of different names, e.g.
exports.sanitizePost = functions.database
.ref('/posts/{questionId}/question/{postId}')