Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Please consider using something other than the pymongo save() #2

Open
tonymillion opened this issue Feb 21, 2013 · 0 comments
Open

Comments

@tonymillion
Copy link

save() in pymongo is "brain damaged". Please consider implementing change tracking and using find_and_modify() to update the document.

Rather than just complain about it, here is some sample code which implements change tracking. Its 'almost' drop in (you'll need to implement the key_in_skeleton function)


class Document(dict):

    __fields = ['_id','username', 'age']

    def key_in_skeleton(self, key):
        #implement this properly pls!
        return key in self.__fields


    def __init__(self, *args, **kwargs):
        self.clear_ops()
        dict.__init__(self, *args, **kwargs)

    def __setitem__(self, key, value):
        if self.key_in_skeleton(key):
            t = ('$set', key, value)
            self.__ops[key] = t

        return super(Document, self).__setitem__(key, value)

    def inc(self, key, value=1):
        t = ('$inc', key, value)
        self.__ops[key] = t

    def dec(self, key, value=1):
        t = ('$inc', key, -abs(value))
        self.__ops[key] = t

    @property
    def operations(self):
        change_set_dict = {}

        for key in self.__ops:
            change = self.__ops[key]
            ctype   = change[0]
            key     = change[1]
            value   = change[2]

            temp = change_set_dict.get(ctype)
            if not temp:
                temp = {}
                change_set_dict[ctype] = temp
            temp[key] = value

        return change_set_dict;


    def clear_ops(self):
        self.__ops = {}
        pass


    def save(self, safe=True):
        if hasattr(self, 'pre_save'):
            self.pre_save()

        new = not self.has_key('_id')
        print 'new=', new

        if new:
            if hasattr(self, 'pre_insert'):
                self.pre_insert()
        else:
            if hasattr(self, 'pre_update'):
                self.pre_update()

        col = self.collection()

        ops = self.operations
        print ops
        if new:
            #if this is an insert, generate an ObjectId and continue!
            res = col.find_and_modify(query={'_id':ObjectId()}, update=ops, upsert=True, new=True)
            self._id = res['_id']
            self.update(res)

            if hasattr(self, 'post_insert'):
                self.post_insert()
        else:
            res = col.find_and_modify(query={'_id':self._id}, update=ops, upsert=True, new=True)

            self.update(res)

            if hasattr(self, 'post_update'):
                self.pre_update()

        self.clear_ops()

        if hasattr(self, 'post_save'):
            self.post_save()

        pass

    pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant