I have to disagree, we can make $lookup work with IDs array if we preface it with $match stage.
// replace IDs array with lookup results_x000D_
db.products.aggregate([_x000D_
{ $match: { products : { $exists: true } } },_x000D_
{_x000D_
$lookup: {_x000D_
from: "products",_x000D_
localField: "products",_x000D_
foreignField: "_id",_x000D_
as: "productObjects"_x000D_
}_x000D_
}_x000D_
])
_x000D_
It becomes more complicated if we want to pass the lookup result to a pipeline. But then again there's a way to do so (already suggested by @user12164):
// replace IDs array with lookup results passed to pipeline_x000D_
db.products.aggregate([_x000D_
{ $match: { products : { $exists: true } } },_x000D_
{_x000D_
$lookup: {_x000D_
from: "products",_x000D_
let: { products: "$products"},_x000D_
pipeline: [_x000D_
{ $match: { $expr: {$in: ["$_id", "$$products"] } } },_x000D_
{ $project: {_id: 0} } // suppress _id_x000D_
],_x000D_
as: "productObjects"_x000D_
}_x000D_
}_x000D_
])
_x000D_