prop
We write a simple prop function which safely looks up properties on your object. If they are present, we get a Just-wrapped value, otherwise we get Nothing -
const fromNullable = x =>
  x == null
    ? Nothing
    : Just(x)
const prop = k => t =>
  fromNullable(t[k])
props
You have nested properties though, so let's make it so we can dig arbitrarily deep into your object using any sequence of props -
const props = (k, ...ks) => t =>
  ks.length
    ? prop(k)(t).bind(props(...ks))
    : prop(k)(t)
validate
Now we can write a simple validate coroutine -
function* validate (t)
{ const id = yield props("user", "id")(t)
  const username = yield props("user", "username")(t)
  const email = yield props("user", "email")(t)
  const post = yield props("post", "content")(t)
  const date = yield props("post", "date")(t)
  return Just({ id, username, email, post, date }) // <- Just(whateverYouWant)
}
const doc = 
  { user:
      { id: '123'
      , username: 'kibe'
      , email: 'blabla@gmail.com'
      }
  , post:
      { content: 'my new post!'
      , date: '20/02/2004'
      }
  }
coroutine(validate(doc)).bind(console.log)
With a valid doc we see -
{
  id: '123',
  username: 'kibe',
  email: 'blabla@gmail.com',
  post: 'my new post!',
  date: '20/02/2004'
}
With an invalid document, otherdoc -
const otherdoc = 
  { user:
      { id: '123'
      , username: 'kibe'
      ,                           // <- missing email
      }
  , post:
      { content: 'my new post!'
      ,                           // <- missing date
      }
  }
coroutine(validate(otherdoc)).bind(console.log)
// no effect because validate returns a Nothing!
coroutine
Implementation of coroutine is simple and most importantly it is generic for any monad -
function coroutine (f)
{ function next (v)
  { let {done, value} = f.next(v)
    return done ? value : value.bind(next)
  }
  return next()
}
Maybe
Lastly we supply implementation for Nothing and Just -
const Nothing = 
  ({ bind: _ => Nothing })
  
const Just = v =>
  ({ bind: f => f(v) })
demo
Expand the snippet below to verify the results in your own browser -
const Nothing = 
  ({ bind: _ => Nothing })
  
const Just = v =>
  ({ bind: f => f(v) })
 
const fromNullable = x =>
  x == null
    ? Nothing
    : Just(x)
const prop = k => t =>
  fromNullable(t[k])
  
const props = (k, ...ks) => t =>
  ks.length
    ? prop(k)(t).bind(props(...ks))
    : prop(k)(t)
 
function coroutine (f)
{ function next (v)
  { let {done, value} = f.next(v)
    return done ? value : value.bind(next)
  }
  return next()
}
function* validate (t)
{ const id = yield props("user", "id")(t)
  const username = yield props("user", "username")(t)
  const email = yield props("user", "email")(t)
  const post = yield props("post", "content")(t)
  const date = yield props("post", "date")(t)
  return Just({ id, username, email, post, date })
}
const doc =
  {user:{id:'123',username:'kibe',email:'blabla@gmail.com'},post:{content:'my new post!',date:'20/02/2004'}}
coroutine(validate(doc)).bind(console.log)
 
 
related reading