Beispiel #1
0
func convertToUpdate(namespace string, obj, oplogEntry bson.M) (*operation.Op, error) {
	op := operation.Op{Namespace: namespace, Type: "update"}
	id, ok := oplogEntry["o2"].(bson.M)["_id"]
	if !ok {
		return nil, fmt.Errorf("Update missing o._id field %#v\n", oplogEntry)
	}

	var err error
	op.ID, err = convertIdToString(id)
	if err != nil {
		return nil, err
	}

	// Check to make sure the object only has $ fields we understand
	// Note that other Mongo update commands (afaict) are converted to either direct
	// set commands or $set and $unset commnands. For example an $addToSet command
	// becoomes {"$set" : {"key.1" : "value"}}
	for key := range obj {
		if strings.Contains(key, "$") && key != "$set" && key != "$unset" {
			return nil, fmt.Errorf("Invalid key %s in update object %#v\n", key, oplogEntry)
		}
	}
	op.Obj = obj

	// Technically cmd.applyOp supports "upserts" on updates ("b" -> "upsert"), but AFAICT
	// they never come from oplogs. See comment for oplogEntryToOp for details.
	if _, ok = oplogEntry["b"]; ok {
		return nil, fmt.Errorf("Unknown field 'b' in update %#v\n", oplogEntry)
	}
	return &op, nil
}
func TestUpdate(t *testing.T) {
	db := setupDb(t)

	// Update a doc and check that it's changed
	obj := bson.M{"_id": bson.NewObjectId(), "key": "value"}
	assert.NoError(t, db.C("test").Insert(obj))

	updatedObj := bson.M{"key": "value2"}

	op := operation.Op{
		ID:        obj["_id"].(bson.ObjectId).Hex(),
		Type:      "update",
		Namespace: "throttle.test",
		Obj:       updatedObj,
	}
	assert.NoError(t, applyOp(op, db.Session))

	var result bson.M
	assert.NoError(t, db.C("test").Find(bson.M{}).One(&result))
	assert.Equal(t, "value2", result["key"].(string))

	// Try with the $set syntax
	op.Obj = bson.M{"$set": bson.M{"key": "value3"}}

	assert.NoError(t, applyOp(op, db.Session))
	assert.NoError(t, db.C("test").Find(bson.M{}).One(&result))
	assert.Equal(t, "value3", result["key"].(string))

	// Updating a doc that doesn't exist doesn't fail
	op.ID = bson.NewObjectId().Hex()
	assert.NoError(t, applyOp(op, db.Session))
}
Beispiel #3
0
func convertToInsert(namespace string, obj bson.M) (*operation.Op, error) {
	op := operation.Op{Namespace: namespace, Type: "insert"}
	id, ok := obj["_id"]
	if !ok {
		// This is valid for indexes, so let's see if the key field exists, and if so assume it's an index
		if _, ok := obj["key"]; ok {
			return nil, nil
		}
		return nil, fmt.Errorf("Insert missing or 'o._id' field %#v\n", obj)
	}

	var err error
	op.ID, err = convertIdToString(id)
	if err != nil {
		return nil, err
	}
	op.Obj = obj
	return &op, nil
}