按日期范围查询Firestore

时间:2017-10-29 13:42:10

标签: firebase google-cloud-firestore

我需要帮助来查询带有日期范围的长集合。请参阅以下示例文档。我想使用日期范围查询startTime字段。

enter image description here

enter image description here

12 个答案:

答案 0 :(得分:49)

由于我在云端防火墙上存储了'dueDate'字段作为时间戳(而不是字符串数字),我这样做是为了获取发票文件到期日2017年:

        let start = new Date('2017-01-01');
        let end = new Date('2018-01-01');

        this.afs.collection('invoices', ref => ref
            .where('dueDate', '>', start)
            .where('dueDate', '<', end)
        );

注意: dueDate字段存储在带有Date()对象的firebase中。例如:this.doc.dueDate = new Date('2017-12-25')

答案 1 :(得分:13)

您可以将日期时间对象存储为Unix time(自1970年1月1日起的秒数)。然后你可以简单地使用where选择这样:

collectionRef.where("startTime", ">=", "1506816000").where("startTime", "<=", "1507593600")

顺便说一下 - 要在你的应用程序中从datetime转换为Unix时间,你可以使用优秀的库moment(如果你用js或节点构建一些东西)。

答案 2 :(得分:11)

years <- c(1990:1994, 1996, 1997, 1999:2002)
years
# 1990 1991 1992 1993 1994 1996 1997 1999 2000 2001 2002

答案 3 :(得分:2)

解决方案是使用Date.now(),停止使用来自firebase的时间戳服务,你需要使用时间的数值,例如:1514271367000,如果firestore使用26/12/2017 1 :56:07 GMT-0500(-05)不起作用。查询的示例是:

    this.fsService.afs.collection('chats/4bY1ZpOr1TPq8bFQ3bjS/finance/123+finance/12345'
      , ref => ref.orderBy('hour').startAt(1514184967000).endAt(1514271367000))
      .valueChanges().subscribe(data =>{
        this.mensajes = data;
      })

答案 4 :(得分:2)

适用于最近使用firbase firestore的每个人。根据您的Firebase实施设置,会有差异。 (或取决于Firebase版本)

之前,firestore将时间戳保存为数据,但是如here in the docs所述,它将很快被Timestamp对象替换。参见Timestamp docs here

您可以通过在代码中添加一个设置来强制Firebase使用Timestamp对象而不是Date 来强制实施。

   var firebaseApp = firebase.initializeApp({
        apiKey: [APIKEY],
        authDomain: [FIREBASEAPPDOMAIN],
        projectId: [PROJECTID]
   });

   var firestore = firebase.firestore();
   var settings = { timestampsInSnapshots: true }; // force Timestamp object instead of Date
   firestore.settings(settings);

答案 5 :(得分:2)

由于 startTime 存储为 Timestamp,您可以执行此查询范围以获得更准确的信息(这对长日期范围或相同日期范围的情况都有好处)。

const start = new Date('2021-01-01T00:00:00.000z');
const end = new Date('2021-03-01T23:59:59.000z');

db.collection('Data').where('startTime', '>=', start).where('startTime', '<=', end).get().then(data => {
   //pass your 'data' here
});

我在我的 Node.js 应用程序中使用了它。希望这有用。

答案 6 :(得分:1)

像我一样使用PHP访问Firestore的人可以执行以下操作:

$startTime = new DateTime('2020-05-23 00:00:00');
$endTime = new DateTime('2020-06-23 23:59:59');

$start = new Google\Cloud\Core\Timestamp($startTime);
$end = new Google\Cloud\Core\Timestamp($endTime);

// fb is a Google\Cloud\Firestore\FirestoreClient object
$this->query = $this->fb->collection('your_collection');

$aux = $this->query;
$aux = $aux->where('startTime', '<', $end);
$aux = $aux->where('startTime', '>', $start);

return $aux->documents();

享受。

答案 7 :(得分:0)

在前端应用程序中,这就是Firebase时间戳和日期可用于查询和存储文档的方式。

Firestore date usage

答案 8 :(得分:0)

var startfulldate = admin.firestore.Timestamp.fromDate(new Date(1556062581000));
db.collection('mycollection')
  .where('start_time', '<=', startfulldate)
  .get()
  .then(snapshot => {              
        var jsonvalue: any[] = [];
        snapshot.forEach(docs => {
          jsonvalue.push(docs.data())
           })
             res.send(jsonvalue);
             return;
            }).catch( error => {
                res.status(500).send(error)
            });

答案 9 :(得分:0)

用于按特定字段的日期范围在集合中查找文档的通用函数:

# This code adapted from https://github.com/python-pillow/Pillow/issues/4644 to resolve an issue
# described in https://github.com/python-pillow/Pillow/issues/4640
#
# There is a long-standing issue with the Pillow library that messes up GIF transparency by replacing the
# transparent pixels with black pixels (among other issues) when the GIF is saved using PIL.Image.save().
# This code works around the issue and allows us to properly generate transparent GIFs.

from typing import Tuple, List, Union
from collections import defaultdict
from random import randrange
from itertools import chain

from PIL.Image import Image


class TransparentAnimatedGifConverter(object):
    _PALETTE_SLOTSET = set(range(256))

    def __init__(self, img_rgba: Image, alpha_threshold: int = 0):
        self._img_rgba = img_rgba
        self._alpha_threshold = alpha_threshold

    def _process_pixels(self):
        """Set the transparent pixels to the color 0."""
        self._transparent_pixels = set(
            idx for idx, alpha in enumerate(
                self._img_rgba.getchannel(channel='A').getdata())
            if alpha <= self._alpha_threshold)

    def _set_parsed_palette(self):
        """Parse the RGB palette color `tuple`s from the palette."""
        palette = self._img_p.getpalette()
        self._img_p_used_palette_idxs = set(
            idx for pal_idx, idx in enumerate(self._img_p_data)
            if pal_idx not in self._transparent_pixels)
        self._img_p_parsedpalette = dict(
            (idx, tuple(palette[idx * 3:idx * 3 + 3]))
            for idx in self._img_p_used_palette_idxs)

    def _get_similar_color_idx(self):
        """Return a palette index with the closest similar color."""
        old_color = self._img_p_parsedpalette[0]
        dict_distance = defaultdict(list)
        for idx in range(1, 256):
            color_item = self._img_p_parsedpalette[idx]
            if color_item == old_color:
                return idx
            distance = sum((
                abs(old_color[0] - color_item[0]),  # Red
                abs(old_color[1] - color_item[1]),  # Green
                abs(old_color[2] - color_item[2])))  # Blue
            dict_distance[distance].append(idx)
        return dict_distance[sorted(dict_distance)[0]][0]

    def _remap_palette_idx_zero(self):
        """Since the first color is used in the palette, remap it."""
        free_slots = self._PALETTE_SLOTSET - self._img_p_used_palette_idxs
        new_idx = free_slots.pop() if free_slots else \
            self._get_similar_color_idx()
        self._img_p_used_palette_idxs.add(new_idx)
        self._palette_replaces['idx_from'].append(0)
        self._palette_replaces['idx_to'].append(new_idx)
        self._img_p_parsedpalette[new_idx] = self._img_p_parsedpalette[0]
        del(self._img_p_parsedpalette[0])

    def _get_unused_color(self) -> tuple:
        """ Return a color for the palette that does not collide with any other already in the palette."""
        used_colors = set(self._img_p_parsedpalette.values())
        while True:
            new_color = (randrange(256), randrange(256), randrange(256))
            if new_color not in used_colors:
                return new_color

    def _process_palette(self):
        """Adjust palette to have the zeroth color set as transparent. Basically, get another palette
        index for the zeroth color."""
        self._set_parsed_palette()
        if 0 in self._img_p_used_palette_idxs:
            self._remap_palette_idx_zero()
        self._img_p_parsedpalette[0] = self._get_unused_color()

    def _adjust_pixels(self):
        """Convert the pixels into their new values."""
        if self._palette_replaces['idx_from']:
            trans_table = bytearray.maketrans(
                bytes(self._palette_replaces['idx_from']),
                bytes(self._palette_replaces['idx_to']))
            self._img_p_data = self._img_p_data.translate(trans_table)
        for idx_pixel in self._transparent_pixels:
            self._img_p_data[idx_pixel] = 0
        self._img_p.frombytes(data=bytes(self._img_p_data))

    def _adjust_palette(self):
        """Modify the palette in the new `Image`."""
        unused_color = self._get_unused_color()
        final_palette = chain.from_iterable(
            self._img_p_parsedpalette.get(x, unused_color) for x in range(256))
        self._img_p.putpalette(data=final_palette)

    def process(self) -> Image:
        """Return the processed mode `P` `Image`."""
        self._img_p = self._img_rgba.convert(mode='P')
        self._img_p_data = bytearray(self._img_p.tobytes())
        self._palette_replaces = dict(idx_from=list(), idx_to=list())
        self._process_pixels()
        self._process_palette()
        self._adjust_pixels()
        self._adjust_palette()
        self._img_p.info['transparency'] = 0
        self._img_p.info['background'] = 0
        return self._img_p


def _create_animated_gif(images: List[Image], durations: Union[int, List[int]]) -> Tuple[Image, dict]:
    """If the image is a GIF, create an its thumbnail here."""
    save_kwargs = dict()
    new_images: List[Image] = []

    for frame in images:
        thumbnail = frame.copy()  # type: Image
        thumbnail_rgba = thumbnail.convert(mode='RGBA')
        thumbnail_rgba.thumbnail(size=frame.size, reducing_gap=3.0)
        converter = TransparentAnimatedGifConverter(img_rgba=thumbnail_rgba)
        thumbnail_p = converter.process()  # type: Image
        new_images.append(thumbnail_p)

    output_image = new_images[0]
    save_kwargs.update(
        format='GIF',
        save_all=True,
        optimize=False,
        append_images=new_images[1:],
        duration=durations,
        disposal=2,  # Other disposals don't work
        loop=0)
    return output_image, save_kwargs


def save_transparent_gif(images: List[Image], durations: Union[int, List[int]], save_file):
    """Creates a transparent GIF, adjusting to avoid transparency issues that are present in the PIL library

    Note that this does NOT work for partial alpha. The partial alpha gets discarded and replaced by solid colors.

    Parameters:
        images: a list of PIL Image objects that compose the GIF frames
        durations: an int or List[int] that describes the animation durations for the frames of this GIF
        save_file: A filename (string), pathlib.Path object or file object. (This parameter corresponds
                   and is passed to the PIL.Image.save() method.)
    Returns:
        Image - The PIL Image object (after first saving the image to the specified target)
    """
    root_frame, save_args = _create_animated_gif(images, durations)
    root_frame.save(save_file, **save_args)

包装:

public List<QueryDocumentSnapshot> findDocsByDateRange(String collection, 
                                                       String fieldStartDate,
                                                       String fieldEndDate,
                                                       Date startDate, 
                                                       Date endDate) {
    ApiFuture<QuerySnapshot> querySnapshot = fireStore()
                    .collection(collection)
                    .whereGreaterThanOrEqualTo(FieldPath.of(fieldStartDate), startDate)
                    .whereLessThanOrEqualTo(FieldPath.of(fieldEndDate), endDate)
                    .get();
    return querySnapshot.get().getDocuments();
}

答案 10 :(得分:0)

我认为这会对你有所帮助,

yourMethod() {
    var date = DateTime.now();//
    print("First Date > " + DateTime(date.year, date.month, 1).toString());
    var datex = new DateTime(date.year, date.month + 1, 0);
    print("Last Date > " +datex);//
    //
    Firestore.instance
        .collection('biling')
        .where("driverId", isEqualTo: widget.uid)
        .where("date",
            isGreaterThanOrEqualTo:
                new DateTime(date.year, date.month, 1).toString())//1
        .where("date", isLessThanOrEqualTo: datex.toString())//2
        .orderBy('date', descending: true)
        .getDocuments()
        .then(
          (QuerySnapshot snapshot) => {
            snapshot.documents.forEach((f) {
              if (this.mounted) {
                setState(() {
                  totalP += double.tryParse(f.data["price"]);
                });
              }
              print("_price " + f.data["price"]);
              print("_duePaymntForCompay " + f.data["duePaymntForCompay"]);
            }),
          },
        );
  }

答案 11 :(得分:-1)

对我有用的是 使用 Moment JS 格式化日期并拆分为日、月和年

const currentDate = moment().format("DD-MM-YYYY").split("-");
const currentDay = currentDate[0];
const currentMonth = currentDate[1];
const currentYear = currentDate[2];


const allDocuments = await collectionRef
.doc(docId)
.collection(*COLLECTION NAME*)
.where(
  *DATE PARAMETER NAME*,
  ">=",
  new Date(`${currentYear}-${currentMonth}-${currentDay}`)
)
.where(
  *DATE PARAMETER NAME*,
  "<",
// ${parseInt(currentDay) + *Number of days you want in range*} 
  new Date(`${currentYear}-${currentMonth}-${parseInt(currentDay) + 1}`)
)
.get();