0

假设我在 mongodb 中删除了一个文档或子文档。我可以创建与删除的_id 相同的文档/子文档吗?在这种情况下,我们假设,我们不能进行更新操作,只能删除和创建。

例如使用 Mongoid(用于 mongodb 的 Rails gem):我们有 Person Model

class Person
    include Mongoid::Document
    field :a, :type => String
    embeds_many :personattributes
end
class Personattribute
    include Mongoid::Document
    field :myattribute, :type => String
    embedded_in :person
end

在我的 Rails 控制器中

class MyController < ApplicationController
    ...
    @the_attributes=@person.personattributes.entries
    ... 
    #controller will render page, an instance variable @the_attributes will be available as JSON in clientside
end

然后用户进行一些客户端数据修改。他们可以向该人员数据添加 1 个或多个人员属性。他们可以对其属性进行一些更改。他们也可以删除一些。全部在客户端。

然后通过 AJAX 调用,用户将修改后的数据以 JSON 格式发回,例如

[{_id:"5253fd494db79bb271000009",myattribute:"test"},{...},...]

控制器中的检索器检索数据然后将人员内部的属性列表完全替换为新的。完全删除和插入,没有更新。

class MyController < ApplicationController
...
@person.personattributes.delete_all #delete all attributes a @person has
attributes=params[:attributes]
attributes.map {|attr| 
    Personattribute.new(:_id => Moped::BSON::ObjectId.from_string(attr["_id"].to_s), :myattribute => attr["myattribute"])
}

@person.personattributes=attributes
@person.save

...
end

我可以这样做吗?它只是意味着,删除所有,插入所有并重用_id。

如果没有,我很乐意就更好的方法获得一些建议。

我不能做 upsert,因为删除的文档需要另一个循环来处理。

谢谢

4

2 回答 2

1

是的,您可以继续使用相同的_id. 它们只需要在集合中是唯一的——这仅适用于文档的_id.

任何ObjectId您可能在文档(或子文档)的另一个字段中使用的任何内容都不需要是唯一的,除非您创建了一个索引,它必须是唯一的。

于 2013-10-08T13:52:37.613 回答
1

Yes, you can do it but I would recommend you not to do that. It seems to have lots of security issues if someone modifies the array manually

I could send:

[{_id:"5253fd494db79bb271000009",myattribute:"test_modified"},{...},...]

or even:

[{_id:"my_new_id_1",myattribute:"test_modified"},{...},...]

which would raise an exception

Moped::BSON::ObjectId.from_string "my_new_id_1" #=> raises an Exception

Try something like:

attributes=params[:attributes]
attributes.each do |attr|
   @person.personattributes.find(attr["_id"]).myattribute = attr["myattribute"]
   #or @person.personattributes.find(attr["_id"]).try(:myattribute=,attr["myattribute"])
end

Probably in a future you want to change the action and send just the modified personattributes in the array instead of all the personattributes. What would you do then if you delete_all and rebuild personattributes with just the sent personattributes?

EDIT

This handles personattributes updates. Create or delete personattributes should go in different actions:

Create action

@person.personattributes.push Personattribute.new(my_attribute: params[:my_attribute])

Delete action

@person.personattributes.delete(params[:personattribute_id])
于 2013-10-08T13:25:09.520 回答