My application has both facebook and twitter users. Now users can merge two accounts together which means they can login with either facebook or twitter account.
Right now, I have a model like this.
{ "_id" : ObjectId("51103a3e69931d2f03000001"), "email" : "email", "id" : "twitter_id", "token" : "token", "secret" : "secret"}
{ "_id" : ObjectId("51103a3e69931d2f03000001"), "email" : "email", "id" : "facebook_id", "token" : "token", "secret" : ""}
Now if these two accounts are the same and the user decided to merge or connect one of his account to something else. How should I change this model effectively and performance as well. I am thinking of having another object called
{"linked_ids" : ["facebook_id", "linkedin_id" ]}
in both accounts. So, the data would be like this. Once merged.
{ "_id" : ObjectId("51103a3e69931d2f03000001"), "email" : "email", "id" : "twitter_id", "token" : "token", "secret" : "secret", "linked_id" : ["facebook_id"] }
{ "_id" : ObjectId("51103a3e69931d2f03000001"), "email" : "email", "id" : "facebook_id", "token" : "token", "secret" : "", "linked_id" : ["twitter_id"] }
Not sure if this would be the best way for performance and scalability?
Why not have one user document in a user collection from the start? You could model it this way instead:
{
"_id" : ObjectId("..."),
"username" : "bob123",
"accounts" : [
{
"email": "email",
"id": "twitter_id",
"token": "token",
"secret": "secret",
"type" : "Twitter"
},
{
"email": "email",
"id": "facebook_id",
"token": "token",
"secret": "",
"type" : "Facebook"
}
]
}
Mongo has plenty of operations to deal with arrays. You can add to them, update one item in the array only, etc.
Doing joins with Mongo introduces complexity that it isn't good at handling as of now. You'd have to do that "join" in your application.
Also this model means you can add any other forms of authentication in one document.
Related
I am working on an application and I need to move the Stripe payment data I have saved around in my user model. I am looking for the best way of doing this. My current data is stored at user.stripe.<value> but I want to move it to user.company.stripe.<value>
Is there tools out there that can handle moving this data around for me or will I need to create a tool to handle this myself? I will be doing a decent amount of this type of data movement during a major refactor (more like a rewrite) so making a tool if non exists is okay with me just no idea how to migrate the data and other Stack Overflow posts are not being of much use that I have found.
Probably picked a bad day/time to post too... Hopefully someone can help me out with examples or direction on where to go from here.
What I want the data to look like:
{ "_id" : ObjectId("5b89c571d855a23b5b07fe95"), "company" : { "customForms" : [ ], "subUserCount" : 1, "stripe" : { "plan" : "<plan Name>", "customerId" : "cus_<ID>", "last4" : "4242", "subscriptionId" : "sub<ID>", "isCoupon" : false } }, "email" : "john.doe#example.ca", "password" : "$2a$10$gMbdy5Dh9Ym..xbVAvhaJO2xhVARAL3oXvad/fX4zAcCuZB88tR1C", "role" : "company", "companyID" : "da89bdee-4123-444c-b221-d41212320a90", }
Current data format:
{ "_id" : ObjectId("5b89c571d855a23b5b07fe95"), "company" : { "customForms" : [ ], "subUserCount" : 1 }, "stripe" : { "plan" : "testplan2", "customerId" : "cus_<ID>", "last4" : "4242", "subscriptionId" : "sub_<ID>", "isCoupon" : false }, "isVerified" : true, "email" : "john.doe#example.ca", "password" : "$2a$10$gMbdy5Dh9Ym..xbVAvhaJO2xhVARAL3oXvad/fX4zAcCuZB88tR1C", "role" : "company", "companyID" : "da89bdee-4123-444c-b221-d41212320a90" }
I want to insert a new item into an embedded array , but before that I need to make sure that that item does not exist already in the array :
thats the collection
"Accounts":[
{
"Account_id" : 70,
"FirstName" : "name",
"LastName" : "bffff",
"Username" : "deee",
"Password" : "xyzqds#j",
"AccountType" : "admin",
"Created_at" : "01-01-2018",
"Rules" : {
"Goal" : 480,
"DoNotDisturbFrom" : "22",
"DoNotDisturbTo" : "8",
"Frequency" : "weekly"
}
},
{
"Account_id" : 52,
"FirstName" : "joe",
"LastName" : "Doe",
"Username" : "aajengui1",
"Password" : "abc#j",
"AccountType" : "user",
"Created_at" : "01-02-2018",
"Rules" : {
"Goal" : 260,
"DoNotDisturbFrom" : "10",
"DoNotDisturbTo" : "12",
"Frequency" : "monthly"
}
}
]
I want to append a new account into the array but it has to be unique so it's like verifying that the username / email does not exist already
Your schema design has a major limitation: if you have enough accounts, the document could be larger than 16 MB, which is the maximum document size in MongoDB.
If applicable to your use case, a better solution is to create accounts as a separate collection, instead of being an array in a single document. This will achieve two things:
You will not be limited to the 16 MB limitation if you have enough accounts in your system.
To add a new account while verifying that the new account username is unique, you can create a unique index on the accounts collection. Trying to insert a document with a duplicate username will result in an error.
I actually managed to do this that solved m problem :
data = request.get_json()
findOneuser=customers.find({"Customer_id": customer_id, "Accounts.Username": data["Username"]},
{"Accounts.Username.$": 1, "_id": 0})
print(findOneuser.count())
if findOneuser.count() == 0:
customers.update(
{"Customer_id": customer_id},
{"$addToSet": {
"Accounts":
{
"Account_id": data["Account_id"],
"FirstName": data["FirstName"],
"LastName": data["LastName"],
"Username": data["Username"],
"AccountType": "user",
"Created_at": data["Created_at"]}
here it's an Api where I get the new account data in JSON format
> findOneuser
will verify if the user exists than append it to the accounts array
Suppose I have a user with few tokens in database. One of those tokens have access: 'unauth', and others as : 'auth' in the db. I am trying to get access via one of the token, the token that I am using...has access as 'unauth' in db. So ideally User info should not be retrieved using that specific token. How come User.findOne() still gets resolved ??
User's snapshot
{
"_id" : ObjectId("5a56798ebf68677d469c8226"),
"updatedAt" : ISODate("2018-01-10T20:43:30.895Z"),
"createdAt" : ISODate("2018-01-10T20:37:34.081Z"),
"email" : "test#testing.com",
"password" : "somepwd",
"tokens" : [
{
"access" : "unauth",
"token" : "dfdgdgfgdfgdfgdfgfdgfddfg",
"_id" : ObjectId("5a56798ebf68677d469c8227")
},
{
"access" : "auth",
"token" : "gjhjjjhhhjhhjjhjhjhjjjjjjjjjghfgh",
"_id" : ObjectId("5a567a0ebf68677d469c8229")
}
],
"__v" : 4
}
User.findOne({
'_id': '5a56798ebf68677d469c8226',
'tokens.access': 'auth',
'tokens.token': 'dfdgdgfgdfgdfgdfgfdgfddfg'
})
Apparently I managed to do it...., the reason it was showing result was because Mongodb finds every element with any of those property in the array. For anyone who stumbles on it...as referenced in docs to search on a nested array element the syntax is => ("arrayName":{ $elemMatch: {"key1" : "value1", "key2" : "value2"}, "key":"value"});
So right now i got alot of ways to login to my app via facebook/google/github and more.
but the thing is that for each services i got almost the same data about me, especially the email address and right now for each services meteor creates new account and i was wondering how can i check to see if some user in my DB is already using a certain email (which is unique of course) and instead of creating a new user just extend the services object and if there is no such user yet then create it.(or similar)
(example of extending ):
(user clicks login via facebook):
{ "createdAt" : ISODate("2013-11-03T17:13:14.232Z"),
"_id" : "xxx", "services" : { "facebook" : { "accessToken" :xxx", "expiresAt" : xxx, "id" : "1841894180", "email" : "xxx", "name" : "Boaz Hoch", "first_name" : "Boaz"
and so on
then after logging out and login with google the user object will look like this:
{ "createdAt" : ISODate("2013-11-03T17:13:14.232Z"),
"_id" : "xxx", "services" : { "facebook" : { "accessToken" :xxx", "expiresAt" : xxx, "id" : "1841894180", "email" : "xxx", "name" : "Boaz Hoch", "first_name" : "Boaz" and more of facebook...} //end of facebook service, google:{ { "accessToken" :xxx", "expiresAt" : xxx, "id" : "1841894180", "email" : "xxx", "name" : "Boaz Hoch", "first_name" : "Boaz" and more
any best practice for this?
i think i have found what i was looking for, here:Using Meteor Accounts package to link multiple services
going to test it now see if its working.
after if tested it, seems to be working smooth!
My first adventure into Mongo. Please save me some time by answering the following. This is the schema.
"_id" : 1,
"FullName" : "Full Name",
"Email" : "email#email.com",
"FacebookId" : NumberLong(0),
"LastModified" : ISODate("2012-04-11T09:26:10.955Z"),
"Connections" : [{
"_id" : 7,
"FullName" : "Fuller name",
"Email" : "connections#email.com",
"FacebookId" : NumberLong(0),
"LastModified" : ISODate("0001-01-01T00:00:00Z")
},
....
Given an id of a single top user, i'd like to return all of the Emails in the Connections array, and preferably, just the emails. What's the querystring? Much obliged!
You can't get only values from the sub-objects in MongoDB.
If you do a query like this:
db.test.find({"_id": 1}, {"Connections.Email":1});
you will get this kind of response:
{
"_id": 1,
"Connections" : [ {"Email":"connections#email.com"},
{"Email":"foo#example.com"} ]
}
This is the closest you can get with a simple query and field selection from MongoDB.
You can then filter out the e-mails values in your code with a simple foreach.