在一个请求中更新不同模型的两个文档

时间:2015-08-09 14:11:42

标签: node.js mongodb express mongoose

假设我正在开发Polling应用程序的后端。用户在轮询中选择一个选项,并且请求更新轮询文档和用户文档。

// Express endpoint for /vote/:pollId/:optionIndex
// (middleware puts users document on req.user)
function(req, res) {

    //Check if the user has already voted on this poll
    ...

    Polley.findByIdAndUpdate(req.params.pollId, {
        //increment the number of votes on the selected options by one
        $inc: ...
    }, {
        new: true
    }, function (err, data) {
        //If err send error message
        ...

        // Now update the users document, so that the user 
        // can't vote on this poll again and so the user can go
        // back and see what he/she voted for.
        User.findByIdAndUpdate( req.user._id,
            {
                $push: {
                    votes: {
                        polleyId: req.params.polleyId,
                        optionIndex: req.params.optionIndex
                    }
                }
            },
            function (err, user) {
                // HERE IS THE PROBLEM. 
                // what if error happens here? Then the user will be able
                // to vote on this poll one more time since the vote was not
                // successfully saved in the users document.
            }
        );

        res.status(200).json({ poll_votes: data.votes, message: "Vote Successful." });
    });
}

我删除了...部分,因为实施与问题无关。

这两项操作都需要在一次通话中进行,以便用户无权更新民意调查文件而非用户文件。

正如我在代码中所说的那样,问题在于,如果我首先更新民意调查文档并在之后更新用户文档,则第一个操作可能会成功,而第二个操作则不会。

如何确保这两项操作都失败或成功?

1 个答案:

答案 0 :(得分:1)

MongoDB不支持不同集合和事务的原子更新。要回答你的问题,我会看到两种方法:

  1. 使用Two Phase Commits
  2. 模拟针对不同馆藏的交易
  3. 将您的数据结构迁移到允许您进行原子操作的public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_home, container, false); ListView listViewPlaces = (ListView) rootView.findViewById(R.id.listLocality); List<PlacesView> lstPlaceView = new ArrayList<PlacesView>(); ArrayList<PlaceModel> listPlaces = getArguments().getParcelableArrayList("listPlaces"); for (int i = 0; i < listPlaces.size(); i++) { Log.d("id", listPlaces.get(i).getId()); PlacesView mv = new PlacesView(listPlaces.get(i), R.layout.list_row_places); lstPlaceView.add(mv); } CustomListAdapter adapter = new CustomListAdapter(lstPlaceView, rootView.getContext()); listViewPlaces.setAdapter(adapter); return rootView; } (例如Google Docs)。
  4. 我可以建议使用TokuMX(它支持事务)而不是MongoDB但问题的标签你指向patching way,其中使用Tokumx为此目的不可能由于事务与线程。
  5. 如果您需要支持交易并且需要使用MongoDB,我建议尝试nodejs,因为这是解决您任务的最简单方法。