5

我正在考虑使用 firebase 作为网络应用程序用户数据的数据存储。我目前的想法是使用他们加入时的时间戳作为引用该用户数据的键来存储每个用户的数据。这种方案的优点是它是一种为用户分配唯一整数 id 的简单方法,并使用户的时间排序变得简单。

然而,一个缺点是,如果两个add user请求使用相同的数据提交,应用程序会很高兴地添加两个单独的条目,这是不理想的。我可以随意调整(我开始认为我应该使用电子邮件作为键并通过连接数据而不是我当前的方案来确定优先级),但假设我不想这样做。有什么方法可以防止重复数据吗?

天真的方法可能只是做类似的事情:

if(!searchFirebaseForUser(data)) {
    addUser(data);
}

但这绝对是一种竞争条件;两个请求很容易同时查询并在数据库中找不到用户,并且都添加。我想在事务中执行此操作,但 Firebase 事务支持似乎并未涵盖这种情况。有没有办法处理这个?

4

4 回答 4

9

您可能必须使用用户名或电子邮件地址作为密钥,并尝试以原子方式写入该位置。

这是来自事务函数参考的相关代码示例。在这种情况下,我们将wilma其用作用户的密钥。

// Try to create a user for wilma, but only if the user id 'wilma' isn't already taken.
var wilmaRef = new Firebase('https://SampleChat.firebaseIO-demo.com/users/wilma');
wilmaRef.transaction(function(currentData) {
  if (currentData === null) {
    return {name: {first: 'Wilma', last: 'Flintstone'} };
  } else {
    console.log('User wilma already exists.');
    return; // Abort the transaction.
  }
}, function(error, committed, snapshot) {
  if (error)
    console.log('Transaction failed abnormally!', error);
  else if (!committed)
    console.log('We aborted the transaction (because wilma already exists).');
  else
    console.log('User wilma added!');
  console.log('Wilma\'s data: ', snapshot.val());
});
于 2013-09-04T22:16:55.520 回答
4

安全规则是否不足以强制执行唯一性?我不知道它们是否是原子的。

{
    "rules": {
        "users": {
            "$username": {
                ".write": "!data.exists()"
            }
        }
    }
}
于 2013-09-07T08:55:29.170 回答
1

您可以使用push自动生成按时间顺序递增的 ID,即使它们是同时创建的,也不会与其他客户端冲突(它们中有一个随机组件)。

例如:

var ref = new Firebase(URL);
var record = ref.push(userInfo);
console.log("User was assigned ID: " + record.name());
于 2013-09-03T18:05:09.910 回答
-2

而不是在 fire-base 数据库中定义规则,防止重复条目的最简单方法是首先从 fire-base 数据库中获取所有数据,并将其与要存储的数据(新数据)进行比较,如果它匹配使用以前的数据,然后再次丢弃存储在数据库中,否则存储在数据库中。请检查下面以获得更清晰的信息。

public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private BroadcastReceiver mRegistrationBroadcastReceiver;
private TextView txtRegId, txtMessage;
DatabaseReference databaseArtists;
ListView listViewArtists;
public static String regId;
List<Artist> artistList;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
txtRegId = (TextView) findViewById(R.id.regid);
txtRegId.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            displayFirebaseRegId();
            boolean flag=false;
            String tokenId=regId;
            for(Artist a:artistList)
            {Log.d("RAaz",a.getTokenId()+"    "+tokenId);
                if(a.getTokenId().equalsIgnoreCase(tokenId))
                {
                    flag=true;
                    Toast.makeText(MainActivity.this, "True", Toast.LENGTH_SHORT).show();
                }
            }
            if(flag)
            {
                Toast.makeText(MainActivity.this, "User Already Exists", Toast.LENGTH_SHORT).show();
            }
            else {
                addArtist();
            }
        }
    });
    mRegistrationBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            // checking for type intent filter
            if (intent.getAction().equals(Config.REGISTRATION_COMPLETE)) {
                // gcm successfully registered
                // now subscribe to `global` topic to receive app wide notifications
                FirebaseMessaging.getInstance().subscribeToTopic(Config.TOPIC_GLOBAL);
                displayFirebaseRegId();
            } else if (intent.getAction().equals(Config.PUSH_NOTIFICATION)) {
                // new push notification is received
                String message = intent.getStringExtra("message");
                Toast.makeText(getApplicationContext(), "Push notification: " + message, Toast.LENGTH_LONG).show();
                txtMessage.setText(message);
            }
        }
    };
    displayFirebaseRegId();
    databaseArtists = FirebaseDatabase.getInstance().getReference("artist");
    artistList = new ArrayList<>();}

下面的代码用于向 Firebase 添加数据

private void addArtist() {
    String name = "User";
    String genre = regId;
    if (!TextUtils.isEmpty(name)) {
        String id = databaseArtists.push().getKey();
        Artist artist = new Artist(id,genre,name);
        databaseArtists.child(id).setValue(artist);
        Toast.makeText(this, "Artist Added", Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(this, "Please enter name", Toast.LENGTH_SHORT).show();
    }
}

使用 onStart 从 firebase 数据库中获取详细信息

protected void onStart() {
    super.onStart();
    Toast.makeText(this, "On Start", Toast.LENGTH_SHORT).show();
    databaseArtists.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            artistList.clear();
            for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
                Artist artist = dataSnapshot1.getValue(Artist.class);
                artistList.add(artist);
            }
        }
        @Override
        public void onCancelled(DatabaseError databaseError) {
        }
    });
}

最后添加 pojo 类

public class Artist {
private String artistId;
private String tokenId;
private String roleName;

public Artist() {
}

public Artist(String artistId, String tokenId, String roleName) {
    this.artistId = artistId;
    this.tokenId = tokenId;
    this.roleName = roleName;
}

public String getArtistId() {
    return artistId;
}

public void setArtistId(String artistId) {
    this.artistId = artistId;
}

public String getTokenId() {
    return tokenId;
}

public void setTokenId(String tokenId) {
    this.tokenId = tokenId;
}

public String getRoleName() {
    return roleName;
}

public void setRoleName(String roleName) {
    this.roleName = roleName;
}

}

于 2017-07-24T06:18:18.283 回答