Get user from identityId - amazon-dynamodb

I saved one element in dynamodb using the id with AWS.config.credentials.identityId and restricting with ${cognito-identity.amazonaws.com:sub}
This generates a us-east-1:14b37fe3-xxxx-xxxx-xxxx-xxxxxxxxxxxx record in dynamodb for a user with sub in cognito user pool: 20a3902b-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Now, I need to create an trigger in dynamodb and retrieve some user attributes like name and email to generate a billing, how I can retrieve this info?
I have tried using this function:
response = boto3.client('cognito-idp').list_users(
UserPoolId='us-east-1_rYoyNTF4V',
AttributesToGet=[
'email', 'name', 'middle_name'
],
Filter='sub = "{sub}"'.format(sub=sub)
)
But it's only works for the 20a3902b-xxxx-xxxx-xxxx-xxxxxxxxxxxx sub.

Related

Get User Details along with login count as per dates in Cosmos DB

Data store in UserActivity Document,
A)User Data
User along with Date store in document only once per day with Type User:
{
"id":"R6788F9DS8DF099K90K0977K", //Unique Id
"UserId":1,
"LoginDate":"2022-04-02T12:41:45.567",
"UserName":"Foo",
"Type":"User"
}
B)LoginAttempt
User login Attept data store in Document with Type LoginAttemt as many times user attempt login
{
"id":"CP6788F9DS8DF099K90K056U", //Unique Id
"UserId":1, //user id for logged in attempted by user
"LoginDate":"2022-04-02T12:41:45.567",
"Type":"LoginAttempt"
},
{
"id":"CP6788F9DS8DF099K90K056U", //Unique Id
"UserId":1, //user id for logged in attempted by user
"LoginDate":"2022-04-02T01:50:20.142",
"Type":"LoginAttempt"
}
I want to achieve below query in Azure Cosmos DB
Select c,
UserName,
LoginDate,
(select count(id) from UserActivity u where u.Type='LoginAttemt' and u.UserId=u1.UserId and u.LoginDate=u1.LoginDate ) LoginCount
from UserActivity u1 where u1.Type='User' and u1.LoginDate='02-04-2022'
but LoginCount is always 0 when I try above query in Cosmos DB.
expected Output will be:
[{
"UserName":"Foo",
"LoginDate":"02-04-2022",
"LoginCount":"2"
}]
above result show user details and logged in count 2 because User Foo Attempted 2 login on date 02-04-2022
and also my Doubt is :
In MSSQL we can pass Outer row details to inner query and inner query process based on received inputs from outer query and return data is it possible in cosmos db

Require unique username when Users container has userId as partition key

I am using this article as an example
https://learn.microsoft.com/en-us/azure/cosmos-db/how-to-model-partition-example with a Users container with userId and username and the partition key as userId.
{
"id": "54c7da13-f4b8-4668-90dc-7c1aa968a73e",
"userId": "54c7da13-f4b8-4668-90dc-7c1aa968a73e",
"type": "user",
"username": "jeffw"
}
In my create user page I want to make sure the username is unique before adding a new user. I tried a pre-trigger but found that "You can't run stored procedures or triggers across multiple logical partitions." How do I make sure that when a user is created that they have selected a unique username? I think I could change the partition key to username but why does the article use userId instead?
SOLUTION
See answer from #mark-brown.
Create a unique key on the Users container and /username:
await database.Database.DefineContainer(name: "Users", partitionKeyPath: "/userId")
.WithUniqueKey().Path("/username").Attach()
.CreateIfNotExistsAsync();
Then try to create a new User with userId as "unique_username" and the new username that is attempting to be created:
{
"id": "06af2937-4677-4d27-a167-5517aa6d0ffd",
"userId": "unique_username",
"type": "unique_username",
"username": "jeffw"
}
await _usersContainer.CreateItemAsync(uniqueUser, new PartitionKey("unique_username"));
This will return a Conflict status if the username already exists. Example is here https://github.com/jwidmer/AzureCosmosDbBlogExample/blob/master/BlogWebApp/Services/BlogCosmosDbService.cs
Changing the partition key to username won't help because you can have multiples of that value in your container. One way you could do this is to have a new partition where you store a unique instance for every user name and use a unique index on the container (unique indexes are unique within a logical partition).
Create a new type = "unique_user" and a userId = "unique_user". Then add a new record of that type with the new username as they register. This should get you millions of users without going over the 20GB limit. Then when creating a new user do an insert on the container with the "unique_user" type and id with the new username. If you get a 201 then do another insert with type= "user" and the rest of the user data.
hope that helps.
You can set up an index policy for unique values.

How to trigger onCreate() when a new field is created in an existing Firestore document?

I want to create a new node in firebase realtime database when a field is created in an existing Firestore document.
I have been trying this:
exports.addUserCredentials = functions.firestore
.document(`Users/{UserID}/{username}`)
.onCreate((snapshot, context) => {
const newUserData = snapshot.data()
const newUserUsername = newUserData
const newUserUidDoc = context.params.UserID
return admin.database().ref(`/userCredentials/${newUserUsername}`).set({"UID": newUserUidDoc})
})
I have searched around the web I saw the path must be directed towards a document only and not a collection. BUT username in the path is a FIELD in the document.
I am getting this error while deploying and I have seen all similar questions but those didn't perfectly answered mine:
! functions: failed to update function addUserCredentials
HTTP Error: 400, The request has errors
The reason is can't change my path to Users/{UserID} which will make my code run perfectly is the fields of document are not added at once.
Here is screenshot of my firestore structure:
The 4 fields of document are updated in 2 batches.
The EMAIL and timeCreated fields are added first and those create the document.
While on the other hand, phoneData and username are fields are CREATED [not updated] after 5 seconds of Email and timeCreated.
So if I use onCreate() on the path Users/{UserID}, it will return UNDEFINED to my realtime database as the username field is ABSENT at that instant.
Is there any way to apply onCreate() on a specific field of the document?
[I am doing this to create a separate node which contains username and UID, this is to check if an username exists when a new user is trying to sign up]
So if the node is created with value undefined it will be an issue.
It will be like this:
The EMAIL and timeCreated fields are added first and those create the document. While on the other hand, phoneData and username are fields are CREATED [not updated] after 5 seconds of Email and timeCreated.
No matter what fields are adding once you created a document,it will be considered as an update operation against that document.As you mentioned in the question,there will be no field with field name called username with a document while you creating document.So it is not possible to get the value of username while you creating the document.
According to your explanation the field username will be only available with the onUpdate trigger.
So the code should be something like below
exports.addUserCredentials = functions.firestore
.document(`Users/{UserID}`)
.onUpdate((snapshot, context) => {
const beforeData = snapshot.before.data()
const afterData = snapshot.after.data()
if(!beforeData.username && afterData.username){
return admin.database().ref(`/userCredentials/${newUserUsername}`).set({"UID": newUserUidDoc})
}
})

Firebase: Get the first result and update it

I would like to create into Firebase an "AccountQueues" object that will have account and names or the word "FREE" if it doesn't have account.
AccountQueues
-LEf-OrdKi65WG0NkQSG
AccountID:
"GR215"
Name:
"FREE"
When a user register I would like to take the first FREE AccountID and update it with the name of the user. Thank you for your help. I am developing an ionic 3 mobile app with this functionality.
You could use a query to check for an account that is free and limit it to the first search result. You want to use snapshotChanges() in order to return the key of the object.
returnedKey = null;
this.fireDB.list('AccountQueues', ref => ref.orderByChild('Name').equalTo('FREE').limitToFirst(1)).snapshotChanges().take(1).subscribe(res => {
res.map(doc => {
this.returnedKey = doc.key; //use this key to update object
});
});
Using the returned key from the query you can then update that object
this.fireDB.object(`AccountQueues/${this.returnedKey}`).update({Name:'Bob'});

Firebase,iOS: Appending key-value pair into a child node

I have the following User Table structure in Firebase
As you can see in the user that I have opened, I have a Posts section, inside this post section holds the Id's all articles which have been posted by this user.
The issue I am facing is as follows:
When the user creates a new article it's saved within the Posts Table, after the save I return the newly generated ID which I then pass on to the user table, I trying to insert the newly created ID into the post section of the user, so I assumed the URL would be something like this:
Users/{UserId}/Posts
However all this does it create a new section called posts, it doesn't actually insert the record into the given area.
My code which isn't working is as follows:
let linkPost = [childautoID: true]
FIRDatabase.database().reference().child("Users/\(UserId)/Posts").child(UserId).setValue(linkPost)
FYI the two id's that are currently inside Posts I added manually.
I've also tried the following:
FIRDatabase.database().reference().child("Users/\(UserId)/Posts").setValue(linkPost)
However all this does it remove all existing Id's and then inserts the new id.
I prefer something like this. This automatically append the data without fetching first
FIRDatabase.database().reference().child("Users/\(UserId)/Posts").child(UserId).setValue(true)
To append a key-value pair in Firebase Database child node use this :-
Make a Firebase Database Reference to the Posts node of that currentUser FIRDatabase.database().reference().child("Users").child(FIRAuth.auth()!.currentUser!.uid).child("Posts")
Check if Posts node exists in your user's DB, If not then create one by :- parentRef.setValue([postId : "True"]) in else block.
But if Posts node does exist retrieve it as a NSMutableDictionary , set the new object to it, and then store the updated Dictionary to that node.
func storePostsToDB(postID :String!, userID : String! = FIRAuth.auth()!.currentUser!.uid){
let parentRef = FIRDatabase.database().reference().child("Users").child(userID).child("Posts")
parentRef.observeSingleEventOfType(.Value, withBlock: {(friendsList) in
if friendsList.exists(){
if let listDict = friendsList.value as? NSMutableDictionary{
listDict.setObject("True", forKey: postID)
parentRef.setValue(listDict)
}
}else{
parentRef.setValue([postID : "True"])
}
})
}
Calling the function:-
storePostsToDB("yourPostID")// If you want to store in the currentUser DB
storePostsToDB("yourPostID", userID : otherUserID)//If you want to store the post in some other users database with uid `otherUserID`

Resources