We are trying to save profile views.
We created a schema something like that
{
user: userId,
viewers: []
}
We think the viewers array could have millions of items
So would it make more sense to do it this way?
{
user: userId,
viewer: viewerId
},
{
user: userId,
viewer: viewerId
},
{
user: userId,
viewer: viewerId
}
In this way this collection could have millions of documents
What is the best way to handling this
I think this would be better, it's way more easy to analyze data. And will not cause the limit of 16mb in one document.
{
user: userId,
viewer: viewerId
},
{
user: userId,
viewer: viewerId
},
{
user: userId,
viewer: viewerId
}
Related
I was trying to make a custom logic for signup phoneauth with Firebase that reads phone number from Firestore. If already present it shows "Already exist else register a new account". But while implementing I am getting errors like if and else both are executed or multiple documents are created while registering.
Help me with it or refer to any other article will be a great help.
const onRegisterPress = () => {
firestore().collection('InternData').get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
if(`${doc.data().phoneNumber}` == phoneNumber)
return alert('Already registered. Try to login first')
else{
firestore()
.collection('InternData')
.add({
phoneNumber: phoneNumber,
fullName: fullName,
date: date,
expertiseIn: expertiseIn
}).then(() => {
// navigation.navigate('InternInfo')
console.log('otp screen')
onSubmit(phoneNumber)
})
}
})
})
This query firestore().collection('InternData').get() would fetch all the documents and check each document if the phoneNumber exists on it causing you to execute your conditions multiple times to each documents found on the InternData collection.
For your use-case, I would suggest using the where() method instead. The query should be like this:
firestore()
.collection('InternData')
.where('phoneNumber', '==', phoneNumber)
.get()
The query above will fetch all the documents that match the value of the fieldname: "phoneNumber" with the value of the variable phoneNumber.
For reference, here's a full sample code:
firestore()
.collection('InternData')
.where('phoneNumber', '==', phoneNumber)
.get()
.then((querySnapshot) => {
// If no match is found, create a new document to the collection.
if (querySnapshot.empty) {
firestore()
.collection('InternData')
.add({
phoneNumber: phoneNumber,
fullName: fullName,
date: date,
expertiseIn: expertiseIn
}).then(() => {
// navigation.navigate('InternInfo')
console.log('otp screen')
onSubmit(phoneNumber)
})
} else {
// This will trigger if there's a result for your query.
return alert('Already registered. Try to login first')
}
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
For more information, you may check out this documentations:
Simple Queries
Execute a query
I am trying to create a my-posts page which will consist of all the posts made by the user.
User Schema
const userSchema = new Mongoose.Schema({
email: { type: String},
password: { type: String},
name: { type: String},
createdAt: { type: String},
posts: [{ type: Mongoose.Schema.Types.ObjectId, ref: 'Post'}]
},{
timestamps: true,
});
Posts Schema
const postSchema = new Mongoose.Schema({
name: { type: String},
category: { type: String},
userId: {type: Mongoose.Schema.Types.ObjectId, ref: "User"},
},{
timestamps: true
});
Creating a new post
handler.post(async(req, res) => {
await db.connect();
const newPost = new Post({
name: req.body.name,
category: req.body.category,
userId: req.body.userId
})
const userBy = await User.findById(userId)
const thePost = await newPost.save();
userBy.posts = user.posts.concat(post._id)
await user.save()
await db.disconnect();
});
export default handler;
Retrieve 'My Posts'
export async function getServerSideProps( {query} ) {
await db.connect();
const data = await User.findById(req.query.id).populate("vehicles").lean
await database.disconnect();
const userPosts = data.map(database.convertObj)
return {
props: {
userPosts
}
}
}
I'm not too sure how to pass the current logged in users _id to the getServerSideProps to then query the database for all the posts attached to that user in the posts array. If there is a better way to approach this please let me know or if you know what I am currently doing wrong, thanks.
This is an area where you might want to use a request from the client side to get the data, as suggested by the Nextjs docs rather than using getServerSideProps.
But if you really want to do it with SSR, you can use getServerSideProps and pass in data (like the userId) to getServerSideProps through the context parameter as either a query or a parameter.
If you want to do it as a query, you can get query as a prop, as you are already doing, or you can do it using a param like in this codesandbox example
This question already has answers here:
Cloud Firestore: Enforcing Unique User Names
(8 answers)
Firestore unique index or unique constraint?
(5 answers)
Closed 1 year ago.
I have a simple app, where a user can register with email and password and later on they can change their username. This is my onSignUp method:
onSignUp() {
const { email, password, userName } = this.state;
this.validate({
userName: { minlength: 3, maxlength: 20, required: true },
email: { email: true, required: true },
password: { minlength: 5, required: true },
});
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then((result) => {
firebase
.firestore()
.collection("users")
.doc(firebase.auth().currentUser.uid)
.set({
email,
username,
});
})
.catch((error) => {
this.setState({ error: error.message });
});
}
Later on, I want to give the user opportunity to change their userName. How do I enforce unique userNames? One way I can think of, is first perform query, on firebase to check if such username exist? Is this the right way to do so? Another way (for which I read, but I dont understand fully) is by enforcing firebase rules? If so, how do I create new rule and how do I set unique usernames? Or should I do it both ways?
You can try this function:
const usersColRef = firebase.firestore().collection("users")
async function isUsernameUnique (username) {
try {
const nameDoc = await usersColRef.where("username", "==", username).get()
return !nameDoc.exists
} catch (e) {
console.log(e)
return false
}
}
// Use it as follows (make sure this is in an async function)
if (await isUsernameUnique("myCoolName")) {
//proceed
} else {
alert("Name is already taken. Show some more creativity ;)")
}
I'd recommend storing a separate field called "nameLower" and then pass the entered username in lowercase in the where() query as it's case sensitive, i.e. .where("nameLower", "==", username.toLowerCase())
So I am trying to do an app using React and Firebase and by now everything was fine.
In my app there are a few options to auth a user. Google, Email and Password and also Twitter.
When a user is creating an account using his email I can easily structure how the data will look like in my firestore for that user and I do it that way:
firebase.createUser(
{ email, password },
{
firstName,
lastName,
emailAddress: email,
birthDate: null,
activeStatus: false,
dateJoined: new Date(),
avatarUrl: null,
friends: [],
posts: [
{
content: "I have just joined!",
date: new Date(),
likes: [],
comments: [],
shares: []
}
]
}
).then(() => {
history.push("/login")
})
And the output in my firestore is something like that:
Firestore screen - email
Now I want to structure my data of users that Signed In using Google auth the same way.
This is how my Sign In using Google looks like:
const loginWithGoogle = () => {
firebase.login({ provider: 'google', type: 'popup' })
.then(() => {
localStorage.setItem('authUser', auth)
history.push("/home")
})
.catch(error => {
console.log(error.message)
})
}
And the output in the firestore by the default looks that way: Firestore screen - google
So my question is:
How do I even try to make both auth types collections look the same way? Should I somehow find out that the user is signing in for the first time using google provider and then try to structure that collection or is there a better approach to do that?
Thanks for all responses.
*******************************
For people who are struggling with that:
I did it thanks to #Ajordat response and this is how it looks and works perfectly fine for me:
const loginWithGoogle = () => {
firebase.login({ provider: 'google', type: 'popup' })
.then((user) => {
const fullName = user.profile.displayName.split(" ")
const firstName = fullName[0]
const lastName = fullName[1]
if (user.additionalUserInfo.isNewUser) {
firestore.collection("users").doc(user.user.uid).set({
...user.profile,
firstName,
lastName,
birthDate: null,
activeStatus: false,
dateJoined: new Date(),
friends: [],
posts: [
{
author: firstName + " " + lastName,
content: "I have just joined!",
date: new Date(),
likes: [],
comments: [],
shares: []
}
]
})
} else {
console.log("user exists")
}
localStorage.setItem('authUser', auth)
history.push("/home")
})
.catch(error => {
console.log(error.message)
})
}
You should use the method AdditionalUserInfo.isNewUser() in order to check if it's the first time a user is logging in. It will always be false except that one time, which you need to use to create the user on Firestore as you want it to be.
I have test app where I'm subscribing to a list of todos. But my add new todo mutation also optimistically updates the UI.
The problem is it's now refreshing the entire react view and I have no idea why.
This is the culprit, it happens when I run this mutation:
export default graphql(addItem, {
options: {
fetchPolicy: 'cache-and-network'
},
props: props => ({
onAdd: item =>
props.mutate({
variables: item,
optimisticResponse: {
__typename: 'Mutation',
addItem: { ...item, __typename: 'Item' }
},
update: (proxy, { data: { addItem } }) => {
let data = proxy.readQuery({ query: listItems });
data.listItems.items.push(addItem);
proxy.writeQuery({ query: listItems, data });
}
})
})
})(AddItem);
It turns out that mutating items locally without all the queried fields (in my case "created" is added by the server) causes the entire query mutation to fail but silently. There's a fix on the way: https://github.com/apollographql/apollo-client/issues/3267
Hopefully this helps others starting out!