从 Firebase 为每个特定帖子检索特定数据的比 datasnapshot 更好的方法?返回的位置错误

Posted

技术标签:

【中文标题】从 Firebase 为每个特定帖子检索特定数据的比 datasnapshot 更好的方法?返回的位置错误【英文标题】:Better way than datasnapshot to retrieve specific data from Firebase for each specific post? Location returned is wrong 【发布时间】:2020-05-12 03:02:22 【问题描述】:

需要从 Firebase 检索每个特定事件的 LatitudeLongitude,其中用户在创建事件时还通过在特定位置设置标记来选择事件位置(LatitudeLongitude)。

我遇到的问题是保存的最后一个事件会覆盖所有其他现有事件位置,因此当您点击TextView 将您带到GoogleMaps 以向您显示事件将在哪里发生时,只有最后一个事件的保存的位置出现。但显然每个事件都有其特定的位置。

例如,如果我创建了三个事件并且它们的位置是罗马、柏林和莫斯科,那么将在 GoogleMap 上创建的唯一标记将是莫斯科的事件,因为那是最后保存的位置。

我希望当第二个用户使用每个特定于事件的postid 来点击TextView 时,可以在数据库中找到该事件并将其特定坐标显示在地图上。有人可以帮我实现这一目标吗?我一直在尝试使用datasnapshot 来实现这一目标,但我一直无法找到其他活动地点。我总是只为所有帖子保存最后一个事件的位置。有没有比datasnapshot 更好的方法?

希望下面的图片有助于弄清楚我的数据结构是如何组织的。

Firebase data structure

MapsActivityUser.java

public class MapsActivityUser extends FragmentActivity implements OnMapReadyCallback 

    private GoogleMap map;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps_user);

        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    

    @Override
    public void onMapReady(GoogleMap googleMap) 
        map = googleMap;

        final DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Posts");
        reference.addValueEventListener(new ValueEventListener() 
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
                for (DataSnapshot snapshot : dataSnapshot.getChildren()) 
                    Post post = snapshot.getValue(Post.class);
                    if (post != null) 
                        double latitude = post.getLocation().getLatitude();
                        double longitude = post.getLocation().getLongitude();

                        LatLng location = new LatLng(latitude, longitude);
                        map.addMarker(new MarkerOptions().position(location).title("Event location"));
                        map.moveCamera(CameraUpdateFactory.newLatLngZoom(location, 10));
                     else 
                        Toast.makeText(MapsActivityUser.this, "Event doesn't have location on Map", Toast.LENGTH_SHORT).show();
                    
                
            

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) 

            
        );
    

【问题讨论】:

如果评论此行map.moveCamera(CameraUpdateFactory.newLatLngZoom(location, 10)); 并增加缩放比例,您会看到所有标记吗? @AlexMamo 是的,你是对的,我看到了所有的标记。我怎样才能让它只出现特定事件位置的标记而其他不出现? 请在下面查看我的答案。 【参考方案1】:

您的代码中的问题是使用了以下代码行:

map.moveCamera(CameraUpdateFactory.newLatLngZoom(location, 10));

在for循环内部,这基本上意味着您的相机将被移动到循环中迭代的最后一个位置。但是,如果您增加缩放比例,您将能够看到地图上的所有位置。根据您最后的评论:

我怎样才能使它只出现特定事件位置的标记而其他不出现?

在这种情况下,您应该使用查询。基本上你会告诉 Firebase 只返回一个与你的查询匹配的位置。这应该是这样的:

Query query = reference.orderByChild("locationName").equalTo("locationName");

现在,只需在此 query 上附加一个侦听器并在地图上添加标记。在这种情况下,建议将相机移动到该位置,因为您只能获得一个位置。但请注意,如果您有唯一的位置名称,则此查询将起作用。如果您还存储位置的 id,那么您只能使用如下所示的 DatabaseReference

DatabaseReference locationRef = reference.child(locationId);

附加一个监听器并在地图上添加标记。

编辑:

要获取经纬度,请使用以下代码行:

Query query = reference.orderByChild("postid").equalTo("-LzNDAXtnT6NXYK2XYPK");
ValueEventListener valueEventListener = new ValueEventListener() 
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) 
        for(DataSnapshot ds : dataSnapshot.getChildren()) 
            double latitude = ds.child("location").child("latitude").getValue(Double.class);
            double longitude = ds.child("location").child("longitude").getValue(Double.class);
            Log.d(TAG, latitude + ", " + longitude);
        
    

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) 
        Log.d(TAG, databaseError.getMessage()); //Don't ignore errors!
    
;
query.addListenerForSingleValueEvent(valueEventListener);

【讨论】:

好的,有一个问题——如果该位置是一个有两个子节点(LatitudeLongitude)的节点,它存储位置数据,那么我只做DatabaseReference locationRef = reference.child(location);。因为位置不保存为城市名称,所以它们保存为LongitudeLatitude 坐标 在上图中可以看到位置数据是如何存储在 Firebase 中的 你不认为我这样做会更好DatabaseReference reference = FirebaseDatabase.getInstance.getReference("Posts").child(postid);??? 我已经用获得latitudelongitude 的代码更新了我的答案。请检查一下。 Alex,这不是只返回特定 postid "-LzNDAXtnT6NXYK2XYPK" 的位置吗?我需要当用户点击帖子时,该帖子的特定位置的任何帖子都回来......并且每个帖子都有自己独特的postid......【参考方案2】:

监听集合回调(查询快照), 在回调运行forloop中,您将获得documentchanges类,您将在其中添加,删除,修改指示器,这表明何时添加,删除和修改数据,相应地执行您的逻辑。 要获取文档,请使用 getId,它将返回集合中存在的所有文档 ID。 我不在电脑前,请在 Google 上查看。

我会尽快编辑解决方案。

【讨论】:

您可以编辑您的答案以反映您正在谈论的代码吗?我仍然不知道该怎么做。谢谢

以上是关于从 Firebase 为每个特定帖子检索特定数据的比 datasnapshot 更好的方法?返回的位置错误的主要内容,如果未能解决你的问题,请参考以下文章

Firebase GeoFire,从我当前位置检索具有特定半径的帖子

如何使用 Firebase 实时数据库创建特定用户所有已保存帖子的列表?

未检索到特定集合 Firebase 的数据

如何从 Firebase 实时数据库中检索特定数据?

在特定日期时间从 Oracle 数据库中检索数据,然后在 php 中将它们发布到 firebase

如何使用颤振和飞镖从 Cloud Firestore 检索特定数据?