Try this inside save_post
but please note the code is not tested
$old = get_post_meta($post_id, 'products');
$new = isset ( $_POST['products'] ) ? $_POST['products'] : array();
if ( empty ($new) ) {
// no products selected: completely delete alla meta values for the post
delete_post_meta($post_id, 'products');
} else {
$already = array();
if ( ! empty($old) ) {
foreach ($old as $value) {
if ( ! in_array($value, $new) ) {
// this value was selected, but now it isn't so delete it
delete_post_meta($post_id, 'products', $value);
} else {
// this value already saved, we can skip it from saving
$already[] = $value;
}
}
}
// we don't save what already saved
$to_save = array_diff($new, $already);
if ( ! empty($to_save) ) {
foreach ( $to_save as $product ) {
add_post_meta( $post_id, 'products', $product);
}
}
}