Next.js & MongoDB (without Mongoose) returning empty array - javascript

I'm using API routes in Next.js with sample data from MongoDB. I am trying to return the data from a single object. First time working with MongoDB, so apologies if the answer has been staring me in the face.
I'm getting an empty array returned with the following query:
import { connectToDatabase } from '../../../util/mongodb';
export default async (req, res) => {
const { db } = await connectToDatabase();
const movies = await db
.collection("movies")
.find({ "_id": "573a1395f29313caabce1f51" })
.limit(20)
.toArray();
res.json(movies);
};
Which corresponds to an object like this:
{
"_id": "573a1395f29313caabce1f51",
"fullplot": "some text goes here"
}
What am I missing? Shouldn't .find({_id: "573a1395f29313caabce1f51"}) return that information? Why am I only seeing an empty array? I understand why it's returning an array (I added .toArray()), but that shouldn't impact whether the results are returned or not.
For what it's worth, querying without parameters works properly. No issues with this query:
import { connectToDatabase } from '../../util/mongodb';
export default async (req, res) => {
const { db } = await connectToDatabase();
const movies = await db
.collection("movies")
.find({})
.sort({ metacritic: -1 })
.limit(20)
.toArray();
res.json(movies);
};
Any help is appreciated, thanks in advance!

Needed to cast to an objectID as mentioned in the comments.
https://docs.mongodb.com/manual/reference/operator/aggregation/toObjectId/

Related

how sort with mongoose

I have a little question
I try to sort with mongoose I know the simple way
but I dont know how to do that with data I get in req.body lets say.
I add here a code I try
exports.sortBy = async (req, res, next) => {
const data1 = req.body.data1 //the data i want to sort
const sortBy = req.body.sortBy //sory by price,createdAt,length and more
const downUp = req.body.downUp // 1, -1
console.log(sortBy)
console.log(data1)
const data = await Book.aggregate([
{
$sort: { [sortBy]: downUp }
},
])
res.status(200).json({
status: 'success',
results: data.length,
data
})
}
so I can sort by the data I get in req.body
Try the following:
const data = await Book.sort({sortBy: downUp});
which seems to work and is much easier to read.

How would I properly set a new variable for a json object?

In Node JS I have an endpoint where I am trying to get data from two different mongo collections and when trying to piece the data together I am not able to add another property to the JSON object.
const getLessonWithTopics = async (req, res) => {
const lessonId = req.params.id;
// Get the lesson
Lesson.findOne({_id: lessonId}).exec((err, data) => {
let lesson = data;
Topic.find().where('_id').in(data.topics).exec((err, topics) => {
if(err) res.status(500).send("Error something went wrong");
lesson.associatedTopics = topics;
console.log(lesson);
res.json(lesson)
})
})
}
When logging lesson to console it does not have the associatedTopics property even though through searching online I have found multiple instances where some is saying this is how you would add this property. (Ex. Add new attribute (element) to JSON object using JavaScript )
I have tried using var as well, to see if that would change something (maybe make it mutable) it did not.
** When logging the topics object to console it does log the data that I expected so the variable 'topics' is not the issue **
I'm sure that it is something simple that I am missing and hoping someone with a large brain can help figure this out for me.
Any help would be appreciated, Thank you!
Can you try once with the following code?
const getLessonWithTopics = async (req, res) => {
const lessonId = req.params.id;
// Get the lesson
try {
const lession = await Lession.findOne({ _id: lessonId }).lean()
const topics = await Topic.find({ _id: { $in: lession.topics } }).lean()
lession.associatedTopics = topics
res.json(lesson);
} catch (err) {
console.log(err)
res.status(500)
}

How to use the findOne mongoDB query correctly?

My goal is to get the one product object back depending on the product id i marked in green (out of the whole products array in my mongo DB)
My Backend entry looks as follows:
router.get("/:id", async (req, res)=> {
const mid=req.params.id;
console.log(mid)
const products = await Product.findOne({ id: mid })
console.log(products)
if (products) {
res.send(products);
} else {
res.status(404).send({message:"product not found"})
}
});
Connsole.log(mid) on line three works and it gives the right id back. However when i try to filter that one array depending on the value in line three i always get back the first object of my Database, which is the gopro camera, instead of the right object.
The Output looks as Follows:
632834528
{
_id: '5f9849daf641a82b257d529b',
id: 3484,
agentId: 66343,
title: 'GoPro Camera',
slug: 'gopro',
What am i doing Wrong?
I tried const products = await Product.find({ id: mid }) as well, but it gives me the whole array back instead of just the one object.
I think it's returning a Query. Try:
const products = await Product.findOne({ id: mid }).exec();
This solution worked for me:
I have to use the Expressasynchandler like this:
Edit: This solution might not be the best (see comments on answer above)
router.get("/:id", expressAsyncHandler(async (req, res) => {
const mid=req.params.id;
const products = await Product.findOne({ id: mid })
if (products) {
res.send([products]);
} else {
res.status(404).send({message:"product not found"})
}
}));

How do I return an array of documents using an array of users object ids in mongoose?

I am trying to create a simple back end blog api with user authentication and authorization. It is built with mongoose and express. In my userSchema, I have a property that is an array called "subscribedTo". Here, users can subscribe to different users to get their blogs. The subscribedTo array stores objectIDs of the users that wished to be subscribed too.
Here is my code:
router.get('/blogs', auth, async (req, res) => {
//auth middleware attaches user to the request obj
try {
let blogs = []
req.user.subscribedTo.forEach(async (id) => {
let ownersBlogs = await Blog.find({owner:id})
blogs = [...blogs, ...ownersBlogs]
console.log(blogs)//consoles desired output of users blogs
})
console.log(blogs)//runs first and returns []
res.send(blogs)
}catch(e){
res.status(500).send(e)
}
})
When I use postman for this route it returns [] which is understandable. I can't seem to res.send(blogs) even though the blogs variable returns correctly in the forEach function.
Is there a better way to do this?
You can use without loop like as bellow
Blog.find({ owner: { $in: req.user.subscribedTo } }, function (err, blogResult) {
if (err) {
response.send(err);
} else {
response.send(blogResult);
}
});
OR
send response after loop completed like as bellow
router.get('/blogs', auth, async (req, res) => {
//auth middleware attaches user to the request obj
try {
let blogs = []
let len = req.user.subscribedTo.length;
let i = 0;
if (len > 0) {
req.user.subscribedTo.forEach(async (id) => {
let ownersBlogs = await Blog.find({ owner: id })
blogs = [...blogs, ...ownersBlogs]
console.log(blogs)//consoles desired output of users blogs
i++;
if (i === len) {
//send response when loop reached at the end
res.send(blogs)
}
})
} else {
res.send(blogs);
}
} catch (e) {
res.status(500).send(e)
}
});
You can find all the documents without a foreach loop, use $in
Blog.find({owner:{$in:[array of ids]}});

How can I query a fire store sub-collection with angular?

I am trying to query a Firestore sub collection in an ionic 4 app/angular app. My database looks as follows people(id) ----> tasks(id)
{ description : this is a description about a cat,<br>
title: this is a cat <br>
category: cat }
I am using a Firestore function to query all of the data in the collection. This is what the Firestore function looks like:
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin'
admin.initializeApp()
export const getFeed = functions.https.onCall(async (req,res) =>{
const docs = await
admin.firestore().collection('people').limit(5).get()
return docs.docs.map(doc => {
return {
postID: doc.id,
...doc.data()
}
})
})
the typescript home.ts file looks like this :
const getFeed = this.aff.httpsCallable('getFeed')
this.posts = getFeed({}).subscribe(data=> {
console.log(data)
// this.posts = data
})
}
I've tried to use the array-contains option to query, but it doesn't
work. The array shows up empty on the console.
export const getFeed = functions.https.onCall(async (req,res) =>{
const docs = await
admin.firestore().collection('people').where("category",
"array-
contains", "cat").limit(5).get()
return docs.docs.map(doc => {
return {
postID: doc.id,
...doc.data()
}
})
})
It's not very clear from your question, but it looks like the category field of your database isn't actually a list type field. array-contains only works if the value is a list, not if it's just a single string value. If it's just a string, then use a == filter on it.
I have found workaround by adopting array field type instead of subcollection.
Here is an example of my code:
var coll = this.firestore.collection('credentials', ref => ref.where('tags', 'array-contains-any', ['agile']).orderBy('shortName')); // selects part of collection where roomId = roomStripped, sorted by name
return coll.snapshotChanges();
I have main collection called credentials, and a list of tags in each document.

Categories

Resources