private void UpdateLocationInfo(IDocumentSnapshot document, GeoPoint location)
        {
            var key = document.Id;

            _locationInfos.TryGetValue(key, out var oldInfo);
            var isNew           = oldInfo == null;
            var changedLocation = oldInfo != null && !Equals(oldInfo.Location, location);
            var wasInQuery      = oldInfo != null && oldInfo.InGeoQuery;

            var isInQuery = LocationIsInQuery(location);

            if ((isNew || !wasInQuery) && isInQuery)
            {
                OnDocumentEntered?.Invoke(this, new DocumentEventArgs <T>(document.ToObject <T>(), location));
            }
            else if (!isNew && isInQuery)
            {
                if (changedLocation)
                {
                    OnDocumentMoved?.Invoke(this, new DocumentEventArgs <T>(document.ToObject <T>(), location));
                }
                OnDocumentChanged?.Invoke(this, new DocumentEventArgs <T>(document.ToObject <T>(), location));
            }
            else if (wasInQuery && !isInQuery)
            {
                OnDocumentExited?.Invoke(this, new DocumentEventArgs <T>(document.ToObject <T>()));
            }

            var newInfo = new LocationInfo(location, LocationIsInQuery(location), document);

            _locationInfos.Add(key, newInfo);
        }
        private void ChildRemoved(IDocumentSnapshot document)
        {
            var key  = document.Id;
            var info = _locationInfos[key];

            if (info == null)
            {
                return;
            }
            lock (_lock)
            {
                var location = GeoFire.GetLocationValue(document);
                var hash     = (location != null) ? new GeoHash(location) : null;
                if (hash != null && GeoHashQueriesContainGeoHash(hash))
                {
                    return;
                }

                _locationInfos.Remove(key);

                if (!info.InGeoQuery)
                {
                    return;
                }

                OnDocumentExited?.Invoke(this, new DocumentEventArgs <T>(info.Snapshot.ToObject <T>()));
            }
        }