Caveats of OUTER JOIN on nested JSON value
Use NOT EXISTS:
SELECT *
FROM  (VALUES ('id1'), ('id2'), ('id3')) AS v(id)
WHERE  NOT EXISTS (SELECT FROM content WHERE json_data -&gt;&gt; 'elementId' = v.id);

Or if you prefer a join:
SELECT v.id
FROM  (VALUES ('id1'), ('id2'), ('id3')) AS v(id)
LEFT   JOIN content c ON c.json_data -&gt;&gt; 'elementId' = v.id
WHERE  c.json_data IS NULL -- or use the PK column

Either is an &quot;anti-join&quot;, technically; and both will probably result in the same query plan.
See:

Select rows which are not present in other table

Consider upgrading to a current version of Postgres. 9.4 has reached EOL in Feb 2020.
Index
But even Postgres 9.4 already supports jsonb which (unlike json) allows a GIN index to support your query. See:

How to get particular object from jsonb array in PostgreSQL?
What's the proper index for querying structures in arrays in Postgres jsonb?

Or if you are focused on this query exclusively, a plain btree on an expression should be the optimum:
CREATE INDEX ON content ((json_data -&gt;&gt; 'elementId'));

Related:

PostgreSQL operator uses index but underlying function does not