Trabaja con listas de datos en las plataformas de Apple

Obtén una FIRDatabaseReference

Para leer o escribir en la base de datos, necesitas una instancia de FIRDatabaseReference:

Swift

Nota: Este producto de Firebase no está disponible en el destino de App Clips.
var ref: DatabaseReference!

ref = Database.database().reference()

Objective-C

Nota: Este producto de Firebase no está disponible en el destino de App Clips.
@property (strong, nonatomic) FIRDatabaseReference *ref;

self.ref = [[FIRDatabase database] reference];

Lectura y escritura de listas

Agrega datos a una lista de datos

Usa el método childByAutoId para agregar datos a una lista en aplicaciones multiusuario. Cada vez que se agrega un elemento secundario nuevo a la referencia de Firebase especificada, el método childByAutoId genera una clave única. Cuando se usan estas claves generadas de forma automática para cada elemento nuevo de la lista, varios clientes pueden agregar elementos secundarios a la misma ubicación, al mismo tiempo y sin conflictos de escritura. La clave única que genera childByAutoId se basa en una marca de tiempo. Por lo tanto, los elementos de las listas se ordenan cronológicamente de forma automática.

Puedes usar la referencia a los datos nuevos que muestra el método childByAutoId para obtener el valor de la clave generada automáticamente del elemento secundario o configurar los datos de dicho elemento. Si se llama a getKey en una referencia childByAutoId, se muestra la clave generada de forma automática.

Puedes usar estas claves generadas de manera automática para simplificar la compactación de tu estructura de datos. Para obtener más información, consulta el ejemplo de fan-out de datos.

Detecta eventos secundarios

Los eventos secundarios se activan en respuesta a operaciones específicas que se ejecutan en los elementos secundarios de un nodo a partir de una operación, como un elemento secundario nuevo que se agrega a través del método childByAutoId o un elemento secundario que se actualiza a través del método updateChildValues.

Tipo de evento Uso común
FIRDataEventTypeChildAdded Recupera listas de elementos o detecta elementos agregados a una lista. Este evento se activa una vez por cada elemento secundario existente y otra vez cuando se agrega un elemento secundario nuevo a la ruta de acceso especificada. El agente de escucha recibe una instantánea que contiene los datos del nuevo elemento secundario.
FIRDataEventTypeChildChanged Detecta cambios en los elementos de una lista. Este evento se activa cuando se modifica un nodo secundario. Esto incluye cualquier modificación en los descendientes del nodo secundario. La instantánea que se pasa al agente de escucha de eventos contiene los datos actualizados del elemento secundario.
FIRDataEventTypeChildRemoved Detecta cuando se quitan elementos de una lista. Este evento se activa cuando se quita un elemento secundario inmediato. El resumen que se pasa al bloque de devolución de llamada contiene los datos del elemento secundario que se quitó.
FIRDataEventTypeChildMoved Detecta cambios en el orden de los elementos de una lista ordenada. Este evento se activa cada vez que una actualización hace que se cambie el orden del elemento secundario. Se usa con datos que se ordenan con queryOrderedByChild o queryOrderedByValue.

Cada uno de estos, en combinación, puede ser útil para detectar cambios en un nodo específico de una base de datos. Por ejemplo, una app social de blogs podría usar estos métodos en combinación para supervisar la actividad en los comentarios de una publicación, como se muestra a continuación:

Swift

Nota: Este producto de Firebase no está disponible en el destino de App Clips.
// Listen for new comments in the Firebase database
commentsRef.observe(.childAdded, with: { (snapshot) -> Void in
  self.comments.append(snapshot)
  self.tableView.insertRows(
    at: [IndexPath(row: self.comments.count - 1, section: self.kSectionComments)],
    with: UITableView.RowAnimation.automatic
  )
})
// Listen for deleted comments in the Firebase database
commentsRef.observe(.childRemoved, with: { (snapshot) -> Void in
  let index = self.indexOfMessage(snapshot)
  self.comments.remove(at: index)
  self.tableView.deleteRows(
    at: [IndexPath(row: index, section: self.kSectionComments)],
    with: UITableView.RowAnimation.automatic
  )
})

Objective-C

Nota: Este producto de Firebase no está disponible en el destino de App Clips.
// Listen for new comments in the Firebase database
[_commentsRef
              observeEventType:FIRDataEventTypeChildAdded
              withBlock:^(FIRDataSnapshot *snapshot) {
                [self.comments addObject:snapshot];
                [self.tableView insertRowsAtIndexPaths:@[
                  [NSIndexPath indexPathForRow:self.comments.count - 1 inSection:kSectionComments]
                ]
                                      withRowAnimation:UITableViewRowAnimationAutomatic];
              }];
// Listen for deleted comments in the Firebase database
[_commentsRef
 observeEventType:FIRDataEventTypeChildRemoved
 withBlock:^(FIRDataSnapshot *snapshot) {
   int index = [self indexOfMessage:snapshot];
   [self.comments removeObjectAtIndex:index];
   [self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:kSectionComments]]
                         withRowAnimation:UITableViewRowAnimationAutomatic];
 }];

Detecta eventos de valores

Si bien escuchar para detectar eventos secundarios es la manera recomendada de leer listas de datos, existen situaciones en las que escuchar para detectar eventos de valores en una referencia de lista puede ser útil.

Si agregas un observador de FIRDataEventTypeValuevalue a una lista de datos, el resultado será una lista completa de los datos en forma de una sola DataSnapshot. Si le aplicas un bucle a ese resultado, puedes acceder a cada elemento secundario.

Incluso cuando hay una sola coincidencia para la consulta, la instantánea es una lista, aunque contenga un solo elemento. Para acceder al elemento, debes aplicar un bucle al resultado:

Swift

Nota: Este producto de Firebase no está disponible en el destino de App Clips.
_commentsRef.observe(.value) { snapshot in
  for child in snapshot.children {
    ...
  }
}

Objective-C

Nota: Este producto de Firebase no está disponible en el destino de App Clips.
[_commentsRef
              observeEventType:FIRDataEventTypeValue
              withBlock:^(FIRDataSnapshot *snapshot) {
                // Loop over children
                NSEnumerator *children = [snapshot children];
                FIRDataSnapshot *child;
                while (child = [children nextObject]) {
                  // ...
                }
              }];

Este patrón puede ser útil cuando quieres recuperar todos los elementos secundarios de una lista en una sola operación, en lugar de escuchar para detectar cada evento secundario que se agrega.

Ordena y filtra datos

Puedes usar la clase FIRDatabaseQuery de Realtime Database para recuperar datos ordenados por clave, por valor o por valor del elemento secundario. También puedes filtrar el resultado ordenado de acuerdo con una cantidad específica de resultados o un rango de claves o valores.

Ordena los datos

Para recuperar datos ordenados, comienza por especificar uno de los métodos de ordenamiento, a fin de determinar cómo se presentarán los resultados:

Método Uso
queryOrderedByKey Ordena los resultados según las claves secundarias.
queryOrderedByValue Ordena los resultados según los valores secundarios.
queryOrderedByChild Ordena los resultados según el valor de una clave secundaria especificada o una ruta de acceso secundaria anidada.

Puedes usar solo un método de ordenamiento a la vez. Si llamas a un método de ordenamiento varias veces en la misma consulta, se genera un error.

El siguiente ejemplo demuestra cómo podrías recuperar una lista de las principales publicaciones de un usuario según la cantidad de estrellas que tienen:

Swift

Nota: Este producto de Firebase no está disponible en el destino de App Clips.
// My top posts by number of stars
let myTopPostsQuery = ref.child("user-posts").child(getUid()).queryOrdered(byChild: "starCount")

Objective-C

Nota: Este producto de Firebase no está disponible en el destino de App Clips.
// My top posts by number of stars
FIRDatabaseQuery *myTopPostsQuery = [[[self.ref child:@"user-posts"]
                                      child:[super getUid]]
                                     queryOrderedByChild:@"starCount"];

Esta consulta recupera las publicaciones del usuario desde la ruta de acceso de la base de datos según su ID de usuario, ordenadas de acuerdo con la cantidad de estrellas que recibió cada publicación. Esta técnica de usar ID como claves de índice se denomina “fan-out de datos”. Puedes obtener más información al respecto en Estructura tu base de datos.

La llamada al método queryOrderedByChild especifica la clave secundaria según la que se deben ordenar los resultados. En este ejemplo, las publicaciones se ordenan según el valor del elemento secundario "starCount" en cada una de ellas. Las consultas también se pueden ordenar por campos secundarios anidados si tienes datos con la estructura siguiente:

"posts": {
  "ts-functions": {
    "metrics": {
      "views" : 1200000,
      "likes" : 251000,
      "shares": 1200,
    },
    "title" : "Why you should use TypeScript for writing Cloud Functions",
    "author": "Doug",
  },
  "android-arch-3": {
    "metrics": {
      "views" : 900000,
      "likes" : 117000,
      "shares": 144,
    },
    "title" : "Using Android Architecture Components with Firebase Realtime Database (Part 3)",
    "author": "Doug",
  }
},

En este caso, podemos ordenar nuestros elementos de lista por valores anidados en la clave metrics si especificamos la ruta de acceso relativa al elemento secundario anidado en nuestra llamada queryOrderedByChild.

Swift

Nota: Este producto de Firebase no está disponible en el destino de App Clips.
 
let postsByMostPopular = ref.child("posts").queryOrdered(byChild: "metrics/views")

Objective-C

Nota: Este producto de Firebase no está disponible en el destino de App Clips.
 
FIRDatabaseQuery *postsByMostPopular = [[ref child:@"posts"] queryOrderedByChild:@"metrics/views"];

Para obtener más información sobre cómo se ordenan otros tipos de datos, consulta la sección Cómo se ordenan los datos de las consultas.

Cómo filtrar datos

Para filtrar datos, puedes combinar cualquiera de los métodos de límite o rango con un método de ordenamiento cuando generes una consulta.

Método Uso
queryLimitedToFirst Configura la cantidad máxima de elementos que pueden mostrarse desde el comienzo de la lista de resultados ordenada.
queryLimitedToLast Configura la cantidad máxima de elementos que pueden mostrarse desde el final de la lista de resultados ordenada.
queryStartingAtValue Muestra elementos con un valor igual o superior a la clave o el valor que se especificó según el método de ordenamiento seleccionado.
queryStartingAfterValue Muestra elementos con un valor superior a la clave o el valor que se especificó según el método de ordenamiento seleccionado.
queryEndingAtValue Muestra elementos con un valor inferior o igual a la clave o el valor que se especificó según el método de ordenamiento seleccionado.
queryEndingBeforeValue Muestra elementos con un valor inferior a la clave o el valor especificados, según el método de ordenamiento seleccionado.
queryEqualToValue Muestra elementos con un valor igual a la clave o el valor que se especificó según el método de ordenamiento seleccionado.

A diferencia de los métodos de ordenamiento, las funciones de límite o rango pueden combinarse. Por ejemplo, puedes combinar los métodos queryStartingAtValue y queryEndingAtValue para limitar los resultados a un rango de valores específico.

Limita la cantidad de resultados

Puedes usar los métodos queryLimitedToFirst y queryLimitedToLast a fin de establecer una cantidad máxima de elementos secundarios que se sincronicen para una devolución de llamada determinada. Por ejemplo, si usas queryLimitedToFirst para establecer un límite de 100, inicialmente solo recibes hasta 100 devoluciones de llamada de tipo FIRDataEventTypeChildAdded. Si hay menos de 100 elementos almacenados en la base de datos de Firebase, se activa una devolución de llamada FIRDataEventTypeChildAdded por cada elemento.

A medida que los elementos cambien, recibirás devoluciones de llamadas de tipo FIRDataEventTypeChildAdded por los elementos que ingresen en la consulta y devoluciones de llamadas de tipo FIRDataEventTypeChildRemoved por los elementos que queden fuera para que el número total continúe siendo 100.

El siguiente ejemplo demuestra cómo la app de blog del ejemplo puede recuperar una lista de las 100 publicaciones más recientes de todos los usuarios:

Swift

Nota: Este producto de Firebase no está disponible en el destino de App Clips.
// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
let recentPostsQuery = (ref?.child("posts").queryLimited(toFirst: 100))!

Objective-C

Nota: Este producto de Firebase no está disponible en el destino de App Clips.
// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
FIRDatabaseQuery *recentPostsQuery = [[self.ref child:@"posts"] queryLimitedToFirst:100];

Filtra por clave o valor

Puedes usar queryStartingAtValue, queryStartingAfterValue, queryEndingAtValue, queryEndingBeforeValue y queryEqualToValue a fin de elegir puntos de inicio, finalización y equivalencia arbitrarios para las consultas. Esto puede ser útil para paginar datos o detectar elementos con campos secundarios que tengan un valor específico.

Cómo se ordenan los datos de las consultas

En esta sección, se explica cómo se ordenan los datos en cada uno de los métodos de ordenamiento de la clase FIRDatabaseQuery.

queryOrderedByKey

Cuando ordenas los datos con queryOrderedByKey, los datos se muestran en orden ascendente, según la clave.

  1. Los elementos secundarios con una clave que puede analizarse como un número entero de 32 bits van primero, ordenados en sentido ascendente.
  2. Los elementos secundarios con un valor de string como clave van después y ordenados de manera lexicográfica, en sentido ascendente.

queryOrderedByValue

Cuando usas queryOrderedByValue, los elementos secundarios se ordenan según el valor. Se utilizan los mismos criterios de orden que para queryOrderedByChild, excepto que se usa el valor del nodo en lugar del valor de una clave secundaria especificada.

queryOrderedByChild

Cuando usas queryOrderedByChild, los datos que contienen la clave secundaria especificada se ordenan de la siguiente manera:

  1. Los elementos secundarios cuyas claves secundarias especificadas posean el valor nil irán en primer lugar.
  2. A continuación, aparecerán los elementos secundarios que tengan el valor false en la clave secundaria especificada. Si hay varios elementos secundarios con el valor false, se ordenan lexicográficamente por clave.
  3. A continuación, aparecerán los elementos secundarios que tengan el valor true en la clave secundaria especificada. Si hay varios elementos secundarios con el valor true, se ordenan lexicográficamente por clave.
  4. Luego vienen los elementos secundarios con valor numérico, que se ordenan en sentido ascendente. Si varios elementos secundarios tienen el mismo valor numérico en el nodo secundario especificado, se ordenan según la clave.
  5. Las strings van después de los números y se ordenan de manera lexicográfica, en sentido ascendente. Si varios elementos secundarios tienen el mismo valor en el nodo secundario especificado, se ordenan de manera lexicográfica según la clave.
  6. Los objetos quedan en último lugar y se ordenan de manera lexicográfica según su clave, en orden ascendente.

Desvincula objetos de escucha

Los observadores no detienen de forma automática la sincronización de datos cuando dejas un ViewController. Si un observador no se quita de forma correcta, seguirá sincronizando datos con la memoria local y retendrá los objetos capturados en el cierre del controlador del evento, lo que puede causar fugas de memoria. Cuando ya no necesites un observador, pasa el FIRDatabaseHandle asociado al método removeObserverWithHandle para quitarlo.

Cuando agregas un bloque de devoluciones de llamada a una referencia, se muestra FIRDatabaseHandle. Estos controladores se pueden usar para quitar el bloque de devoluciones de llamada.

Si se agregaron varios objetos de escucha a la referencia de una base de datos, se llama a cada objeto de escucha cuando surge un evento. Para detener la sincronización de datos en esa ubicación, debes quitar todos los observadores de la ubicación a través del método removeAllObservers.

Llamar a removeObserverWithHandle o removeAllObservers en un objeto de escucha no quita de manera automática los objetos de escucha registrados en estos nodos secundarios; también debes hacer un seguimiento de esas referencias o controladores para quitarlos.

Próximos pasos