Task: Need to leverage a given “username” to look up the “_id” of a user in a “users” collection. Then use that “_id” to find all documents in a “cars” collection where the “_id” from the “users” collection matches the “authorId”
Code with Aggregate:
const usersCollection = client.db().collection("users")
let cars = await usersCollection
.aggregate([
// look up id from users given the username
{ $match: { username: username } },
{ $lookup: { from: "cars", localField: "_id", foreignField: "authorId", as: "carDocument" } },
{ $unwind: "$carDocument" },
{
$project: {
_id: 1,
username: 1,
useful_miles: 1,
monthly_miles: 1,
// kind of merge the two together
carId: "$carDocument._id",
authorId: "$carDocument.authorId",
description: "$carDocument.description",
price: "$carDocument.price",
miles: "$carDocument.miles",
link: "$carDocument.link",
createdDate: "$carDocument.createdDate"
}
}
])
.toArray()
Output:
{
username: 'pepper',
useful_miles: 150000,
monthly_miles: 1250,
cars: {
authorId: new ObjectId("62728d8c6f59729aaf25f53d"),
description: '2017 Honda HR-V EX AWD',
price: 17250,
miles: 73516,
link: 'https://www.whatEvs.com/blippidty-bloppity-boop',
createdDate: 2022-05-04T14:28:28.420Z
}
}
Some notes on the aggregate:
Is there a way to run the “toString” method on the “authorId” property to prevent getting the new ObjectId? (Cannot just add “$carDocument._id.toString()” or the propoerty will not be output at all. See docs for a possible solution).
The “$unwind” property is used to only re-spell out as a nested object. You can alternatively just have all on one level.
Code with Query
const usersCollection = client.db().collection("users")
const sessionDoc = await usersCollection.findOne({ username: username })
let sessionId
if (!sessionDoc) {
throw "no session doc"
}
sessionId = sessionDoc._id.toString()
const carsCollection = client.db().collection("cars")
const cars = await carsCollection.find({ authorId: new ObjectId(sessionId) }).toArray()
Output of Query Code
[
{
_id: new ObjectId("627299c16f59729aaf25f53e"),
authorId: new ObjectId("627267346f59729aaf25f539"),
description: '2017 Honda HR-V AWD',
price: 17250,
miles: 73516,
link: 'https://www.cargurus.com/Cars/inventorylisting/viewDetailsFilterViewInventoryListing.action?sourceContext=carGurusHomePageModel&entitySelectingHelper.selectedEntity=&zip=34685#listing=313275506/NONE',
createdDate: 2022-05-04T15:20:32.130Z
},
{
_id: new ObjectId("627299dd6f59729aaf25f53f"),
authorId: new ObjectId("627267346f59729aaf25f539"),
description: '2017 Chevy Equinox LT FWD',
price: 15792,
miles: 81860,
link: 'https://www.cargurus.com/Cars/inventorylisting/viewDetailsFilterViewInventoryListing.action?sourceContext=carGurusHomePageModel&entitySelectingHelper.selectedEntity=&zip=34685#listing=324379551/NONE',
createdDate: 2022-05-04T15:21:00.914Z
}
]
Some notes on the query
Need two steps to get the data, 1.) findOne on users collection and 2.) use find on the cars collection.
Need to return two things into one object manually.
Run one with aggregate but I don’t want the user data on every document, although I do need it.
Is there a metric, (Big O)?