def update_one(self, query, what, upsert=False): assert (len(what) == 1 and ("$set" in what or "$unset" in what or "$push" in what)), \ "$set/$unset/$push operators not found" doc = self.find_one(query) if doc: if "$set" in what: # parse_dot_fields uses json.dumps internally, we can to make # sure everything is serializable first what = json.loads(json.dumps(what, default=json_serial)) what = parse_dot_fields(what["$set"]) doc = update_dict_recur(doc, what) elif "$unset" in what: for keytounset in what["$unset"].keys(): doc.pop(keytounset, None) elif "$push" in what: for listkey, elem in what["$push"].items(): assert "." not in listkey, "$push not supported for nested keys: %s" % listkey doc.setdefault(listkey, []).append(elem) self.save(doc) elif upsert: assert "_id" in query, "Can't upsert without _id" assert "$set" in what, "Upsert needs $set operator (it makes sense...)" doc = what["$set"] doc["_id"] = query["_id"] self.save(doc)
def update_one(self, query, what): assert len(what) == 1 and "$set" in what doc = self.find_one(query) if not doc: raise Exception("No result for query %s" % repr(query)) what = parse_dot_fields(what) doc = update_dict_recur(doc, what) self.save(doc)
def _update_one(self, doc, update, *args, **kwargs): if args or kwargs: raise NotImplementedError() if not len(update) == 1: raise ValueError("Invalid operator.") if next(iter(update)) not in ("$set", "$unset", "$push", "$addToSet", "$pull"): raise NotImplementedError(next(iter(update))) # https://docs.mongodb.com/manual/reference/operator/update/set/ # https://docs.mongodb.com/manual/reference/operator/update/unset/ # https://docs.mongodb.com/manual/reference/operator/update/push/ # https://docs.mongodb.com/manual/reference/operator/update/addToSet/ # https://docs.mongodb.com/manual/reference/operator/update/pull/ if "$set" in update: _update = json.loads(to_json(update["$set"])) _update = parse_dot_fields(_update) doc = update_dict_recur(doc, _update) elif "$unset" in update: for dotk, v in traverse(doc): if dotk in update["$unset"]: v["__REMOVE__"] = True doc = merge({}, doc) elif "$push" in update: for key, val in update["$push"].items(): if "." in key: # not all mongo operators are fully implemented raise NotImplementedError("nested key in $push: %s" % key) doc.setdefault(key, []).append(val) elif "$addToSet" in update: for key, val in update["$addToSet"].items(): if "." in key: # not all mongo operators are fully implemented raise NotImplementedError("nested key in $addToSet: %s" % key) field = doc.setdefault(key, []) if val not in field: field.append(val) else: # "$pull" in update: for key, val in update["$pull"].items(): if "." in key: # not all mongo operators are fully implemented raise NotImplementedError("nested key in $pull: %s" % key) if not isinstance(val, (str, int)): raise NotImplementedError( "value or condition in $pull: %s" % val) if isinstance(doc.get(key), list): doc[key][:] = [x for x in doc[key] if x != val] self._write_one(doc)
def update_one(self, query, what): assert len(what) == 1 and ("$set" in what or \ "$unset" in what or "$push" in what), "$set/$unset/$push operators not found" doc = self.find_one(query) if doc: if "$set" in what: # parse_dot_fields uses json.dumps internally, we can to make # sure everything is serializable first what = json.loads(json.dumps(what, default=json_serial)) what = parse_dot_fields(what["$set"]) doc = update_dict_recur(doc, what) elif "$unset" in what: for keytounset in what["$unset"].keys(): doc.pop(keytounset, None) elif "$push" in what: for listkey, elem in what["$push"].items(): assert not "." in listkey, "$push not supported for nested keys: %s" % listkey doc.setdefault(listkey, []).append(elem) self.save(doc)