Firebase如何以原子方式防止重复条目

时间:2013-09-01 02:20:56

标签: firebase transactions firebase-realtime-database atomic

我正在考虑使用firebase作为Web应用程序用户数据的数据存储。我目前的想法是使用他们加入的时间戳作为引用该用户数据的密钥来存储每个用户的数据。这种方案的优点是,它是一种向用户分配唯一整数ID的简单方法,并且可以简化用户的时间顺序排序。

然而,缺点是,如果两个“添加用户”请求提交的数据相同,那么应用程序将很乐意添加两个单独的条目,这是不理想的。我可以随意乱扔东西(我开始认为我应该使用电子邮件作为密钥并通过连接数据优先考虑,而不是我当前的方案),但我想我不想这样做。有没有办法防止重复数据?

天真的方法可能只是做一些事情:

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

但这绝对是一场竞赛;两个请求都很容易查询并在数据库中找不到用户,并且都添加。我想在一个交易中执行此操作,但似乎Firebase事务支持不包括这种情况。有没有办法解决这个问题?

4 个答案:

答案 0 :(得分:9)

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

以下是transaction函数参考中的相关代码示例。在这种情况下,我们使用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());
});

答案 1 :(得分:4)

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

{
    "rules": {
        "users": {
            "$username": {
                ".write": "!data.exists()"
            }
        }
    }
}

答案 2 :(得分:0)

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

例如:

var ref = new Firebase(URL);
var record = ref.push(userInfo);
console.log("User was assigned ID: " + record.name());

答案 3 :(得分:-2)

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

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;
}

}