This answers the question as asked, but might have a problem generalizing to other situations:
library(dplyr)
library(tidyr)
library(purrr)
df1 = data.frame(V1 = c('A', 'B', 'C', 'D'), v2 = c(1,2,3,4))
df2 = data.frame(VA = c('A', 'B', 'C'), VB = c('D', 'E', 'F'), vC = c(4,5,6))
joined_df <- df1 %>%
nest_join(df2, by = c("V1" = "VA"), keep = TRUE, name = "first_join_condition") %>%
nest_join(df2, by = c("V1" = "VB"), keep = TRUE, name = "second_join_condition") %>%
mutate(ored_join_condition = map2(first_join_condition, second_join_condition, function(x, y) if(nrow(x) == 0) y else x)) %>%
select(-first_join_condition, -second_join_condition) %>%
unnest(ored_join_condition) %>%
full_join(df1, by = c("V1", "v2")) # add back any rows from df1 which didn't match on either condition
I'm not entirely sure, but it feels like this will cause problems if there are multiple lines in df2 which match on both conditions (they would appear duplicated in the output). This will work as a starting point, though!