Cursores de consulta

Os cursores de consultas permitem que uma aplicação obtenha os resultados de uma consulta em lotes convenientes e são recomendados em vez de usar deslocamentos de números inteiros para paginação. Consulte o artigo Consultas para mais informações sobre a estruturação de consultas para a sua app.

Cursores de consulta

Os cursores de consulta permitem que uma aplicação obtenha os resultados de uma consulta em lotes convenientes sem incorrer na sobrecarga de uma compensação de consulta. Após realizar uma operação de obtenção, a aplicação pode obter um cursor, que é uma string codificada em base64 opaca que marca a posição do índice do último resultado obtido. A aplicação pode guardar esta string, por exemplo, no Datastore, no Memcache, num payload de tarefas da fila de tarefas ou incorporada numa página Web como um parâmetro HTTP GET ou POST e, em seguida, pode usar o cursor como ponto de partida para uma operação de obtenção subsequente para obter o lote seguinte de resultados a partir do ponto em que a obtenção anterior terminou. Uma obtenção também pode especificar um cursor final para limitar a extensão do conjunto de resultados devolvido.

Compensações versus cursores

Embora o Datastore suporte deslocamentos de números inteiros, deve evitar usá-los. Em alternativa, use cursores. A utilização de um desvio apenas evita devolver as entidades ignoradas à sua aplicação, mas estas entidades continuam a ser obtidas internamente. As entidades ignoradas afetam a latência da consulta e a sua aplicação é faturada pelas operações de leitura necessárias para as obter. A utilização de cursores em vez de deslocamentos permite-lhe evitar todos estes custos.

Exemplo de cursor de consulta

Em Go, uma aplicação obtém um cursor depois de obter os resultados da consulta chamando o método Cursor do valor Iterator. Para obter resultados adicionais a partir do ponto do cursor, a aplicação prepara uma consulta semelhante com o mesmo tipo de entidade, filtros e ordens de ordenação, e passa o cursor para o método Start da consulta antes de realizar a obtenção:

// Create a query for all Person entities.
q := datastore.NewQuery("Person")

// If the application stored a cursor during a previous request, use it.
item, err := memcache.Get(ctx, "person_cursor")
if err == nil {
	cursor, err := datastore.DecodeCursor(string(item.Value))
	if err == nil {
		q = q.Start(cursor)
	}
}

// Iterate over the results.
t := q.Run(ctx)
for {
	var p Person
	_, err := t.Next(&p)
	if err == datastore.Done {
		break
	}
	if err != nil {
		log.Errorf(ctx, "fetching next Person: %v", err)
		break
	}
	// Do something with the Person p
}

// Get updated cursor and store it for next time.
if cursor, err := t.Cursor(); err == nil {
	memcache.Set(ctx, &memcache.Item{
		Key:   "person_cursor",
		Value: []byte(cursor.String()),
	})
}

Limitações dos cursores

Os cursores estão sujeitos às seguintes limitações:

  • Um cursor só pode ser usado pela mesma aplicação que executou a consulta original e apenas para continuar a mesma consulta. Para usar o cursor numa operação de obtenção subsequente, tem de reconstituir exatamente a consulta original, incluindo o mesmo tipo de entidade, filtro de antepassados, filtros de propriedades e ordens de ordenação. Não é possível obter resultados através de um cursor sem configurar a mesma consulta a partir da qual foi originalmente gerado.
  • Os cursores nem sempre funcionam como esperado com uma consulta que usa um filtro de desigualdade ou uma ordem de ordenação numa propriedade com vários valores. A lógica de remoção de duplicados para essas propriedades com vários valores não persiste entre obtenções, o que pode fazer com que o mesmo resultado seja devolvido mais do que uma vez.
  • Os novos lançamentos do App Engine podem alterar os detalhes de implementação interna, invalidando os cursores que dependem deles. Se uma aplicação tentar usar um cursor que já não é válido, o Datastore devolve um erro.

Cursores e atualizações de dados

A posição do cursor é definida como a localização na lista de resultados após o último resultado devolvido. Um cursor não é uma posição relativa na lista (não é um desvio); é um marcador para o qual o Datastore pode saltar quando inicia uma análise de índice para resultados. Se os resultados de uma consulta mudarem entre utilizações de um cursor, a consulta apenas nota as alterações que ocorrem nos resultados após o cursor. Se aparecer um novo resultado antes da posição do cursor para a consulta, não é devolvido quando os resultados após o cursor são obtidos. Da mesma forma, se uma entidade deixar de ser um resultado para uma consulta, mas tiver aparecido antes do cursor, os resultados que aparecem depois do cursor não mudam. Se o último resultado devolvido for removido do conjunto de resultados, o cursor continua a saber como localizar o resultado seguinte.

Ao obter resultados de consultas, pode usar um cursor de início e um cursor de fim para devolver um grupo contínuo de resultados do Datastore. Quando usa um cursor de início e fim para obter os resultados, não tem a garantia de que o tamanho dos resultados seja o mesmo que quando gerou os cursores. As entidades podem ser adicionadas ou eliminadas do Datastore entre o momento em que os cursores são gerados e o momento em que são usados numa consulta.

O que se segue?