skip to Main Content

I have 2 nodes in my database items and my_items.

I have this function that does a multi-path update, this function deletes an item from items and adds it to the user’s my_items:

I secured the my_items node in a way that you can only write to it if the item exists in items, otherwise it fails:

private void getItem(String uid, String item_key) {    
  Map<String, Object> updates = new HashMap<>();

  //delete item
  updates.put("items/" + item_key, null);

  //give the item to the user
  updates.put("my_items/" + uid + "/" + item_key, itemObject);

  mDatabaseReference.updateChildren(updates);
}

Question (In theory):

  • Knowing that Firebase Database handles requests one by one.

If users A,B,C,D called the getItem(..) function for the same item id together at the same time:

Does this makes sense:

  1. lets say A’s request reached the server first and Succeeds

(now the item was deleted from items and added to user A at my_items)

  1. B: Fails

(because the item no longer exists in items, so security rule of my_items prevents this)

  1. C: Fails

(same reason)

  1. D: Fails

(same reason)

Is this what would happen ? Or I got this wrong ?

Thanks.

2

Answers


  1. This Firebase Blog post discusses atomic operations. RTDB acts on requests as they arrive. RTDB processes events as they arrive. There is another question that might be relevant Does Firebase always guarantee added events in order?

    You can … do this in a single atomic update to both locations:

    JavaScript

    var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
    // Generate a new push ID for the new post
    var newPostRef = ref.child("posts").push();
    var newPostKey = newPostRef.key();
    // Create the data we want to update
    var updatedUserData = {};
    updatedUserData["user/posts/" + newPostKey] = true;
    updatedUserData["posts/" + newPostKey] = {
      title: "New Post",
      content: "Here is my new post!"
    };
    // Do a deep-path update
    ref.update(updatedUserData, function(error) {
      if (error) {
        console.log("Error updating data:", error);
      }
    });
    

    Java

    Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
    // Generate a new push ID for the new post
    Firebase newPostRef = ref.child("posts").push();
    String newPostKey = newPostRef.getKey();
    // Create the data we want to update
    Map newPost = new HashMap();
    newPost.put("title", "New Post");
    newPost.put("content", "Here is my new post!");
    Map updatedUserData = new HashMap();
    updatedUserData.put("users/posts/" + newPostKey, true);
    updatedUserData.put("posts/" + newPostKey, newPost);
    // Do a deep-path update
    ref.updateChildren(updatedUserData, new Firebase.CompletionListener() {
       @Override
       public void onComplete(FirebaseError firebaseError, Firebase firebase) {
           if (firebaseError != null) {
               System.out.println("Error updating data: " + firebaseError.getMessage());
           }
       }
    });  
    

    Objective-C

    Firebase *ref = [[Firebase alloc] initWithUrl: @"https://<YOUR-FIREBASE-APP>.firebaseio.com"];
    // Generate a new push ID for the new post
    Firebase *newPostRef = [[ref childByAppendingPath:@"posts"] childByAutoId];
    NSString *newPostKey = newPostRef.key;
    NSString *updateUserPath = [NSString stringWithFormat:@"users/posts/%@", newPostKey];
    NSString *updatePostPath = [NSString stringWithFormat:@"posts/%@", newPostKey];
    // Create the data we want to update
    NSMutableDictionary *updatedUserData = [[NSMutableDictionary alloc] init];
    [updatedUserData setValue:[NSNumber numberWithBool:YES] forKey:updateUserPath];
    [updatedUserData setValue:@{@"title": @"New Post", @"content": @"Here is my new post!"} forKey:updatePostPath];
    // Do a deep-path update
    [ref updateChildValues:updatedUserData withCompletionBlock:^(NSError *error, Firebase *ref) {
        if (error) {
            NSLog(@"Error updating data: %@", error.debugDescription);
        }
    }];
    

    Swift

    "https://<YOUR-FIREBASE-APP>.firebaseio.com") // Generate a new push
    ID for the new post let newPostRef =
    ref.childByAppendingPath("posts").childByAutoId() let newPostKey =
    newPostRef.key // Create the data we want to update let
    updatedUserData = ["users/posts/(newPostKey)": true,
    "posts/(newPostKey)": > ["title": "New Post", "content": "Here is my
    new post!"]] // Do a deep-path update
    ref.updateChildValues(updatedUserData, withCompletionBlock: { (error,
    ref) -> > Void in
        if (error) {
            print("Error updating data: (error.description)")
        } }) 
    

    Deep path updates let you write cleaner code and easily denormalize
    data across multiple nodes in your Firebase database.

    Login or Signup to reply.
  2. The Firebase Realtime Database processes (write) operations sequentially. So any previous write operation will have been completed before the next one is processed. That means that any data written by a previous user will indeed be present in the root variable in security rules evaluation for later write operations.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search