# Notes

## Realtime Database

See the [Realtime Database docs for web](https://firebase.google.com/docs/database/).

### Set a ref

```javascript
function writeUserData(userId, name, email, imageUrl) {
  firebase
    .database()
    .ref('users/' + userId)
    .set({
      username: name,
      email: email,
      profile_picture: imageUrl,
    });
}
```

### Value events

Value events fire with the entire data payload for any and all changes

> Listen to ongoing events

```javascript
var starCountRef = firebase.database().ref('posts/' + postId + '/starCount');
starCountRef.on('value', function(snapshot) {
  updateStarCount(postElement, snapshot.val());
});
```

> Listen to a single event and stop listening

```javascript
var userId = firebase.auth().currentUser.uid;
return firebase
  .database()
  .ref('/users/' + userId)
  .once('value')
  .then(function(snapshot) {
    var username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
    // ...
  });
```

### Multi-path updates

```javascript
function writeNewPost(uid, username, picture, title, body) {
  // A post entry.
  var postData = {
    author: username,
    uid: uid,
    body: body,
    title: title,
    starCount: 0,
    authorPic: picture,
  };

  // Get a key for a new Post.
  var newPostKey = firebase
    .database()
    .ref()
    .child('posts')
    .push().key;

  // Write the new post's data simultaneously in the posts list and the user's post list.
  var updates = {};
  updates['/posts/' + newPostKey] = postData;
  updates['/user-posts/' + uid + '/' + newPostKey] = postData;

  return firebase
    .database()
    .ref()
    .update(updates);
}
```

### Delete data

```javascript
function deleteUser(userId) {
  return firebase
    .database()
    .ref('/users/' + userId)
    .remove();
}
```

### Detach listener

```javascript
var starCountRef = firebase.database().ref('posts/' + postId + '/starCount');
var listener = starCountRef.on('value', function(snapshot) {
  updateStarCount(postElement, snapshot.val());
});

function detachListener() {
  starCountRef.off('value', listener);
}
```

### Transactions

```javascript
function toggleStar(postRef, uid) {
  postRef.transaction(function(post) {
    if (post) {
      if (post.stars && post.stars[uid]) {
        post.starCount--;
        post.stars[uid] = null;
      } else {
        post.starCount++;
        if (!post.stars) {
          post.stars = {};
        }
        post.stars[uid] = true;
      }
    }
    return post;
  });
}
```

### Child events

* **child\_added**: fires once for every existing result and then again for every new result; does not fire for changes or removals, only new records
* **child\_changed**: fires when the underlying object or value is changed in any way
* **child\_removed**: fires when the entire record is removed

```javascript
var commentsRef = firebase.database().ref('post-comments/' + postId);
commentsRef.on('child_added', function(data) {
  addCommentElement(postElement, data.key, data.val().text, data.val().author);
});

commentsRef.on('child_changed', function(data) {
  setCommentValues(postElement, data.key, data.val().text, data.val().author);
});

commentsRef.on('child_removed', function(data) {
  deleteComment(postElement, data.key);
});
```

### Sort data

* **orderByChild('childName')**: Orders by a child attribute
* **orderByKey()**: Orders by record keys
* **orderByValue()**: Orders by record values; only relevant when values are strings or numbers and not nested objects

```javascript
var topUserPostsRef = firebase
  .database()
  .ref('user-posts/' + myUserId)
  .orderByChild('starCount');

var mostViewedPosts = firebase
  .database()
  .ref('posts')
  .orderByChild('metrics/views');
```

### Filter data

> Assumes that data is ordered by key unless otherwise specified

* **limitToFirst(count)**: Sets the maximum number of items to return from the beginning of the ordered list of results.
* **limitToLast(count)**: Sets the maximum number of items to return from the end of the ordered list of results.
* **startAt(value)**: Return items greater than or equal to the specified key or value, depending on the order-by method chosen.
* **endAt(value)**: Return items less than or equal to the specified key or value, depending on the order-by method chosen.
* **equalTo(value)**: Return items equal to the specified key or value, depending on the order-by method chosen.

```javascript
var first100Days = firebase
  .database()
  .ref('days/2018')
  .orderByChild('dayOfYear')
  .limitToFirst(100);

var first10DaysOfFebruary = firebase
  .database()
  .ref('days/2018')
  .orderByChild('dayOfYear')
  .limitToFirst(10)
  .startAt(32);

var last10DaysOfJanuary = firebase
  .database()
  .ref('days/2018')
  .orderByChild('dayOfYear')
  .limitToLast(10)
  .endAt(31);

var first10DaysOfJanuary = firebase
  .database()
  .ref('days/2018')
  .orderByChild('dayOfYear')
  .limitToFirst(100) // Limit is never hit
  .endAt(10); // endAt stops the query before it hits the limit
```

### Authenticate Node.js

> Full admin privileges

```javascript
var admin = require('firebase-admin');

// Fetch the service account key JSON file contents
var serviceAccount = require('path/to/serviceAccountKey.json');

// Initialize the app with a service account, granting admin privileges
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: 'https://databaseName.firebaseio.com',
});

// As an admin, the app has access to read and write all data, regardless of Security Rules
var db = admin.database();
var ref = db.ref('restricted_access/secret_document');
ref.once('value', function(snapshot) {
  console.log(snapshot.val());
});
```

### Initialize Node.js with limited privileges

> Set auth token variables to limit access

```javascript
// Initialize the app with a custom auth variable, limiting the server's access
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: 'https://databaseName.firebaseio.com',
  databaseAuthVariableOverride: {
    uid: 'my-service-worker',
  },
});
```

> Act as an un-authenticated user

```javascript
// Initialize the app with a custom auth variable, limiting the server's access
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: 'https://databaseName.firebaseio.com',
  databaseAuthVariableOverride: null,
});
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.fullstackfirebase.com/realtime-database/notes.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
