Set up mongodb _id to firebase uid - mongodb

I'm new to asking questions in Stack overflow.
I'm implementing an application that it's using Firebase Auth for users login, logout and delete account and mongodb with python (pymongo) to manage the database.
When a user signs in, a new user is created in Firebase Auth so the new user is given a new UID which is a 28 characters id (it is a string). My idea is to set the value of the _id from mongodb collection to the uid but it seems that the uid is longer than what it is expected:
Here you can see the output in the python console (An exception occurred :: 'g2CgrpStaOUwEFBpLzuJWme3OMR2' is not a valid ObjectId, it must be a 12-byte input or a 24-character hex string)
Do you have any idea to solve this problem? I tried
"_id": ObjectId(str.encode(id)) when creating the document but it says
An exception occurred :: id must be an instance of (bytes, str, ObjectId), not <class 'bytes'> and I'm running out of ideas.
I hope you can help me, I'm glad to hear your questions.
Thanks in advance.
EDIT
As I'm working with Firebase Auth in the frontend (react native + expo app)
#Dharmaraj suggested me to use Firebase Auth admin SDK in the client side so that I can assign a certain uid to the user based on the user _id in mongodb database. Thanks for your suggestion!

The MongoDB object ID is a 12 bytes hex string but Firebase auth's UID is not. You can either store the Firebase UID as string in a different field in document e.g. userId or since your are using MongoDB I assume you must be running this logic on server side. In that case you can first add the user document in MongoDB and use that _ID as Firebase UID. You can specify this custom UID when using Firebase admin SDK

The _id field is mandatory, unique within a collection, and immutable. However it does not have to be an ObjectID.
It often is, as MongoDB will create the field automatically as one, but noting the caveats above, you can set it to a string or indeed any other valid BSON type.
More info: https://www.mongodb.com/docs/manual/core/document/#the-_id-field

Related

MongoDB ObjectId vs string in find()

I'm starting to play with mongodb, and I learned that when inserting a document, you can either provide an ID, or let mongodb generate it for you.
I thought this is nice, because I want to let my users optionally choose an id, and if not generate it for them.
But the problem is, the generated one is of type ObjectId while the user provided one is a string, and the find method only returns the correct answer if you pass it with the correct type. So when a user requests GET /widget/123, I have no idea if the original ID was stored as an ObjectId or a string do I?
So how am I supposed to use this feature?
First off, I'd recommend against letting users provide _ids: if 2 users want to use the same _id, the second user will be unable to, which will be frustrating. If users want that functionality, I'd recommend storing the user created id on a separate field & querying by user (or company or whatever) and the user-created id.
That said, mongo ObjectIds are 24 hex characters, so you can safely identify when an id is not a MongoId by checking whether it doesn't match /^[a-f0-9]{24}$/ (or by seeing whether a call to ObjectId("maybeAnObjectId") throws). In the case where it's unclear (where a user might have provided 24 hex characters as their id), you'll need to use $in (or $or) to query for both cases:
const query = /^[a-f0-9]{24}$/.test(id) ? { _id: {$in: [ObjectId(id), id]}} : {_id: id}
(an annoying user could re-use an autogenerated ObjectId as their string id, and then queries to that route would return two values and there'd be no way of differentiating them).

MongoDB - Stitch: Can't make custom user data to appear in userObject.customData

When I log with a user the userObject contains empty customData object despite saving a document in custom data collection pointing to the app user.
I tried to follow the documentation:
In the Users section of Mongo Stitch panel I enabled custom data. I chose database, collection (users) and stated User ID Field to be userId. Then I deployed changes.
I have a created and confirmed user.
I copied the user's _id and from shell (from admin account and context of the relevant db) I ran command db.users.insertOne({userId: ObjectId('copied_id'), description: "something"}). It was acknowledged and when I query the collection I see relevant document with userId field having correct ObjectId() value.
I even tried to set read rights to the users collection.
Nonetheless, if I log in with my user, customData object is empty. What can be the cause of this?
same issue here... pebcak :/
I fixed it by setting userId as String, not ObjectId.
Hoping it's not too late ;)

MongoDB : Snapchat like notification schema for the database

I've done some research regarding the following subject and I wanted to get advice from more experienced developper to see if my solution was the best one.
If you don't know what Snapchat is, it's a mobile application that let you share pictures with your friends.
What I'am interested in is the notification part of the application, where the user checks if he has received new pictures. It looks like this :
What I want to do is find the best way to check, when the user opens the app or refresh the view, if he has received new images/messages using MongoDB.
After some research the best solution is to have three collections in my Mongo database :
User : User_ID
Username
PasswordHash
...
Where the User_ID is unique and generated by MongoDB
Messages: Message_ID
Message_Content
...
Where the Message_ID is unique and generated by MongoDB. The collection could store other informations like an image URL (images stored in a BLOB), etc.
Notifications : Notification_ID
Sender_ID
Receiver_ID (index)
Message_ID
Where the Notification_ID is unique and generated by MongoDB. The Sender_ID and Receiver_ID are User_ID from the collection User. The Message_ID is from the collection Messages. The Receiver_ID field is indexed.
So when an user launches or refresh the view, I query the collection Notifications with the field Receiver_ID (which is indexed) set to the actual User_ID to find all the messages he may have received. If he has received messages, I query the Messages collection to find all the information about the messages he received (with Message_ID obtained by the previous query one Notifications).
After that, I delete the document(s) on the collection Notifications (if he has not yet opened the messages, I store the Message_ID locally on the device).
To add documents to the Notifications and Messages collections, it is done when an user sends a new message.
The field Receiver_ID from the Notifications collection is indexed to query faster. If I understand correctly indexes with MongoDB, the write operations are a bit slowed down but the reading speed is a lot better. But just to be sure, the Receiver_ID index will be updated automatically when new documents are added to the collection Notifications or I'll have to update it manually ?
Is it the best solution to solve this problem or is there a better one ?
EDIT : There is another question I came accross :
The Receiver_ID field is indexed so I can query faster the Notifications collections. Doing so let me get the Message_ID but after that, I need to query the Messages collection in order to retrieve all the information regarding the message. Should I also index the field Message_ID in the collection messages, knowing that this collection will store all the messages ever sent and it could take some time to find the corresponding message ?
Or is the field _id is automatically indexed by Mongo so I wouldn't need to do that ?
EDIT 2 : Regarding the question from the second EDIT, I found out that I don't need to index the Message_ID because all _id are indexed by default.
MongoDB creates the _id index, which is an ascending unique index on the _id field, for all collections when the collection is created. You cannot remove the index on the _id field.
You can learn more about it here
Thanks for reading !
Here are some links I found when looking for a solution :
Develop Database Schema for Notify like facebook
How to implement instant notification system using Express + Mongo Rest API?
Is it better to store notifications of all users under one collection / table OR rather provide each user his own collection / table to store notifications?
the research provided looks impressive!
Regarding notification process - looks OK - but what if user uses more than one device (tablet, phone etc?) - that need to include device ID and status array per device
Index once created will be maintained by DB engine

Flow Router doesn't work with ObjectID. Any fix?

I'm trying to build routes in my Meteor app. Routing works perfectly fine but getting information from db with route path just doesn't work. I create my page specific routes with this:
FlowRouter.route('/level/:id'...
This route takes me to related template without a problem. Then I want to get some data from database that belong to that page. In my template helpers I get my page's id with this:
var id = FlowRouter.getParam('id');
This gets the ObjectID() but in string format. So I try to find that ObjectID() document in the collection with this:
Levels.findOne({_id: id});
But of course documents doesn't have ObjectIDs in string format (otherwise we wouldn't call it "object"id). Hence, it brings an undefined error. I don't want to deal with creating my own _ids so is there anything I can do about this?
PS: Mongo used to create _ids with plain text. Someting like I would get with _id._str now but all of a sudden, it generates ObjectID(). I don't know why, any ideas?
MongoDB used ObjectIds as _ids by default and Meteor explicitly sets GUID strings by default.
Perhaps you inserted using a meteor shell session in the past and now used a mongo shell/GUI or a meteor mongo prompt to do so, which resulted in ObjectIds being created.
If this happens in a development environment, you could generate the data again.
Otherwise, you could try to generate new _ids for your data using Meteor.uuid().
If you want to use ObjectId as the default for a certain collection, you can specify the idGeneration option to its constructor as 'MONGO'.
If you have the string content of an ObjectId and want to convert it, you can issue
let _id = new Mongo.ObjectID(my23HexCharString);

How to insert new document only if it doesn't already exist in MongoDB

I have a collection of users with the following schema:
{
_id:ObjectId("123...."),
name:"user_name",
field1:"field1 value",
field2:"field2 value",
etc...
}
The users are looked up by the user.name, which must be unique. When a new user is added, I first perform a search and if no such user is found, I add the new user document to the collection. The operations of searching for the user and adding a new user, if not found, are not atomic, so it's possible, when multiple application servers are connect to the DB server, for two add_user requests to be received at the same time with the same user name, resulting in no such user being found for both add_user requests, which in turn results with two documents having the same "user.name". In fact this happened (due to a bug on the client) with just a single app server running NodeJS and using Async library.
I was thinking of using findAndModify, but that doesn't work, since I'm not simply updating a field (that exists or doesn't exist) of a document that already exists and can use upsert, but want to insert a new document only if the search criteria fails. I can't make the query to be not equal to "user.name", since it will find other users.
First of all, you should maintain a unique index on the name field of the users collection. This can be specified in the schema if you are using Mongoose or by using the statement:
collection.ensureIndex('name', {unique: true}, callback);
This will make sure that the name field remains unique and will solve the problem of concurrent requests as you have specified in your question. You do not require searching when this index is set.