into

Specifies in which field the result of the lookup will be stored into.

Specifying this parameter is mandatory.

To learn more about the $lookup stage, see HasLookup.lookup.

Example

class Department(
val _id: ObjectId,
val name: String,
)

class User(
val _id: ObjectId,
val name: String,
val department: ObjectId,
val departments: List<Department>,
)

users.aggregate()
.lookup {
into(User::departments)
from(departments.aggregate())
on(User::department, Department::_id)
}

Arrays and subdocuments

If you specify a field in a subdocument, the subdocument will be created even if no results are found. The field itself will not.

For example:

class Department(
val _id: ObjectId,
val name: String,
)

class DepartmentInfo(
val _id: ObjectId,
val department: Department? = null,
)

class User(
val _id: ObjectId,
val name: String,
val departmentInfo: DepartmentInfo? = null,
)

users.aggregate()
.lookup {
into(User::departmentInfo / DepartmentInfo::department)
from(departments.aggregate())
on(User::departmentInfo / DepartmentInfo::_id, Department::_id)
}

If no departments are found, here is a potential returned user:

{
"_id": { "$oid": "699dfad90ca573f85c0eec1c" },
"name": "Bob",
"departmentInfo": {}
}

Even though no results were found, "departmentInfo" is still set to an empty document. Since DepartmentInfo._id does not have a default value, this request will fail during deserialization (missing mandatory field).

External resources