Ir a la consola
Prueba Cloud Firestore: Descubre la base de datos flexible y escalable de Firebase y Google Cloud Platform. Obtén más información sobre Cloud Firestore.

Trabaja con listas de datos en iOS

Obtén una FIRDatabaseReference

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

Swift

var ref: DatabaseReference!
ref = Database.database().reference()

Objective-C

@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. El método childByAutoId genera una clave única cada vez que se agrega un nuevo elemento secundario a la referencia de Firebase especificada. 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. childByAutoId genera una clave única a partir de una marca de tiempo. Por lo tanto, los elementos de listas se ordenan cronológicamente de forma automática.

Puedes usar la referencia a los nuevos datos que muestra el método childByAutoId para obtener el valor de la clave generada de forma automática del elemento secundario o configurar los datos del elemento secundario. Si llamas 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 distribución de datos.

Detecta eventos secundarios

Los eventos secundarios se activan en respuesta a operaciones específicas que afectan a un elemento secundario de un nodo desde una operación, como cuando se agrega un nuevo elemento secundario a través del método childByAutoId o cuando se actualiza con el 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.La instantánea que se pasa al bloque de devoluciones 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 ordenados mediante 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

// 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

// 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 FIRDataEventTypeValue a una lista de datos, el resultado será una lista completa de datos en forma de una sola instantánea de los datos. 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

_commentsRef.observe(.value) { snapshot in
  for child in snapshot.children {
    ...
  }
}

Objective-C

[_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.

Cómo ordenar y filtrar datos

Puedes usar la clase FIRDatabaseQuery de Realtime Database para recuperar los datos organizados 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 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

// My top posts by number of stars
let myTopPostsQuery = (ref.child("user-posts").child(getUid())).queryOrdered(byChild: "starCount")

Objective-C

// 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 "distribución 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 cual se deben ordenar los resultados. En este ejemplo, las publicaciones se ordenan según el valor del elemento secundario "starCount" de cada publicación. Las consultas también se pueden ordenar por campos secundarios anidados si tienes datos que lucen de la siguiente forma:

"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 los elementos de nuestra lista según los valores anidados en la clave metrics. Para ello, debemos especificar la ruta de acceso relativa al elemento secundario anidado presente en nuestra llamada a queryOrderedByChild.

Swift

 
let postsByMostPopular = ref.child("posts").queryOrdered(byChild: "metrics/views")

Objective-C

 
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 especifica 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 especifica según el método de ordenamiento seleccionado.
queryEqualToValue Muestra elementos con un valor igual a la clave o el valor que se especifica según el método de ordenamiento seleccionado.

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

Limita la cantidad de resultados

Puedes usar los métodos queryLimitedToFirst y queryLimitedToLast para establecer un número máximo de elementos secundarios que se sincronizarán para una devolución de llamada determinada. Por ejemplo, si usas queryLimitedToFirst para establecer un límite de 100, inicialmente solo recibes 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 ejemplo siguiente 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

// 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

// 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, queryEndingAtValue y queryEqualToValue para seleccionar puntos arbitrarios de inicio, término y equivalencia para las consultas. Esto puede ser útil para paginar datos o para encontrar elementos con elementos secundarios que tengan un valor específico.

Cómo se ordenan los datos de consultas

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

queryOrderedByKey

Cuando ordenas 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 elemento entero de 32 bits van primero, ordenados en sentido ascendente.
  2. A continuación, van los elementos secundarios con un valor de string como clave, ordenados de manera lexicográfica, en sentido ascendente.

queryOrderedByValue

Cuando usas queryOrderedByValue, los elementos secundarios se ordenan según su valor. Los criterios de ordenamiento son los mismos que en queryOrderedByChild, excepto por el hecho de 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 de manera lexicográfica según la 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 agentes 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 apropiada, la sincronización de datos continúa en la memoria local. 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 agentes de escucha a la referencia de una base de datos, cada agente de escucha se llama 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.

Si llamas a removeObserverWithHandle o a removeAllObservers en un agente de escucha, no se quitan automáticamente los agentes de escucha registrados en sus nodos secundarios; también debes hacer un seguimiento de esas referencias o esos controladores para quitarlos.

Pasos siguientes