Mongoose findOne variables - mongodb

I have a function which passes a key val and then gets added as arguments for a .findOne() mongoose function.
getByKey = async (key, val) => {
console.log(key, val);
const user = await UserSchema.findOne({
key: val
});
console.log(user);
return user;
};
The problem is, I think mongoose is actually searching the collection for the word key instead of the what it stands for ie: "username" or "age"

It is looking for 'key' as opposed to the key your passing. You can accomplish what you're trying to do by doing something like this.
var query = {}
query[key] = value;
And then pass that query to your findOne function. See below.
getByKey = async (key, val) => {
var query = {}
query[key] = value;
const user = await UserSchema.findOne(query);
console.log(user);
return user;
};
You also might want to consider adding a callback function to in your findOne and try to log the data if it was found.
const user = await UserSchema.findOne(query, function(err, data){
if (err){
console.log(err)
} else {
console.log(data)
}
});

You can use Computed property names to handle this. Example:
const user = await UserSchema.findOne({
[key]: val
});

Related

How can I loop over a list of documents and execute commands on each in mongoose with async await

I have users, posts and follows collection. I want to select posts, limit it to 10 and look their authors in follows collection whether user follow him or not. Also using async and await made me confusing. I tried this code
async function index (req,res){
const {user_id} = req.body
const post = await Post.find().exec( async (err,doc)=>{
const isFollowing = await Follows.find({who_id : user_id , whom_id : doc._id })
if (isFollowing.length > 0){
return doc
}
})
Then I figured out from VS Code that if I use exec function "'await' has no effect on the type of this expression.
You can select 10 random posts and return only the one that the user follows between them with:
async function index (req,res)
{
const { user_id } = req.body
const posts = await Post.find().limit(10);
const following = [];
for (const post of posts) {
const isFollowing = await Follows.find({ who_id : user_id , whom_id : post._id });
if (isFollowing) following.push(post);
}
return following;
})

Mongoose find return an empty array but return values when i set a variable to the model

why is the first query not working
I am using mongoose
i want to e able to check for errors during query that why I want to use the first instance
import Work from './WorkModel.js'
const response = await Work.findOne({ user: userId}).exec((err, result) => {
if (err) {
throw new Error('Try again later');
} else {
console.log(odemruId);
return result;
}
});
return response
//this return no value
const response= await Work.findOne({user: userId})
return response
//this actual works
```

Changing order of an array in mongoose does not save

I am using drag and drop library to change the order of my elements, and I need that order to be saved, the following method does change the document but it won't save it, I tried doc.save() and this update method, the logged doc is in changed order but it's not updated in the database.
module.exports.changeListOrder = async(req, res) => {
const { id, listID, oldIndex, newIndex } = req.body;
await Board.findById(id).then(async(doc) => {
let tmpdoc = doc.lists[oldIndex];
doc.lists[oldIndex] = doc.lists[newIndex];
doc.lists[newIndex] = tmpdoc;
await Board.updateOne({ _id: id }, { $set: { list: doc.lists } })
});
}
and my model has
lists: [{ header: String, listItems: Array }]
You are mixing up Promise and async syntax. The async syntax would be like this:
module.exports.changeListOrder = async (req, res) => {
const { id, listID, oldIndex, newIndex } = req.body;
const thisBoard = await Board.findById(id);
// this code won't run until thisBoard has returned a value
let [oldValue, newValue] = [thisBoard.lists[oldIndex], thisBoard.lists[newIndex];
thisBoard[oldIndex] = newValue;
thisBoard[newIndex] = oldValue;
let saveOperation = await Board.save(thisBoard);
// console.log(saveOperation);
// return saveOperation or do something with res()
};
module.exports.changeListOrder = async(req, res) => {
const { id, listID, oldIndex, newIndex } = req.body;
const doc = await Board.findById(id);
let [oldValue, newValue] = [doc.lists[oldIndex], doc.lists[newIndex]];
doc.lists.set(oldIndex, newValue);
doc.lists.set(newIndex, oldValue);
await doc.save();
};
Here is the working code, the problem was that Mongoose doesn't create getters/setters for array indexes; without them mongoose never gets notified of the change and so doesn't know to persist the new value, so you have to use set()

How to fetch documents coming from different collections in Firestore inside a Redux Saga

I have the following saga:
export function* fetchAnalyticsData() {
try {
const data = [];
const collectionReference = firestore.collection("collection1")
const UIDSreference = yield collectionReference.get();
// getUID is a function that returns an array of UIDS of documents of collection1
const UIDS = yield call(getUID, collectionReference);
const populate = yield all(
UIDS.map((uid) => {
firestore
.collection("collection1")
.doc(uid)
.collection("collection2")
.get()
.then((response) => {
if (response.docs.length) {
response.docs.forEach((doc) => data.push(doc.data()));
console.log(data);
}
});
})
);
console.log(data);
yield put(fetchAnalyticsDataSuccess(data));
} catch (error) {
console.log(`Error in fetchAnalyticsData: ${error}`);
yield put(fetchAnalyticsDataFailure(error.message));
}
}
The inner console.log(data) prints the data array correctly filled. However, the outer console.log(data) prints an empty array. I know it's because these things are promises, but then how can I solve this issue?

Why resolving an async promise with a .map() function doesn't work for GET with parameters?

I am not sure how to express my question correctly.
Basically resolving an async promise with a .map() function works for simple get functions while it doesn't work for get functions with parameter.
Basically, in this case, router.get('/' ... the following works:
import axios from 'axios'
const url = 'http://localhost:3000/api/library/'
class libraryService {
// Get stories
static getStories () {
return new Promise(async (resolve, reject) => {
try {
const res = await axios.get(url)
const data = res.data
resolve(
data.map(story => ({
...story
}))
)
} catch (err) {
reject(err)
}
})
}
export default libraryService
While in this case, router.get('/:story_name' ..., this variation doesn't work:
class readService {
// Get story to read
static getStoryToRead (storyName) {
return new Promise(async (resolve, reject) => {
try {
const res = await axios.get(url + storyName)
const data = res.data
resolve(
data.map(selectedStory => ({
...selectedStory
}))
...
In here I get an error: 'data.map is not a function'.
Changing to data.products.map() will return an error 'Cannot read property 'map' of undefined'.
However resolving data without .map() function will work on all cases:
try {
const res = await axios.get(...)
const data = res.data
resolve(
data
)
...
Why this is happening and is it correct to just use resolve(data)?
You seem to be asking for a single story in the case that doesn't work. So instead of an array of stories, presuambly you're getting just the one story that you asked for. There's no reason to try to use map.
Minimal changes (but keep reading):
// Minimal changes, but keep reading...
static getStoryToRead (storyName) {
return new Promise(async (resolve, reject) => {
try {
const res = await axios.get(url + storyName);
resolve(res.data);
} catch (err) {
reject(err);
}
});
}
But, both of those functions demonstrate the Promise creation antipattern. You already have a promise, work with it. In this case, you'd probably do that by making the functions async:
static async getStories () {
const {data} = await axios.get(url);
return data.map(story => ({ // Why copy the story objects?
...story
}));
}
static async getStoryToRead (storyName) {
const {data} = await axios.get(url + storyName));
return data;
}
Or with non-async functions:
static getStories () {
return axios.get(url)
.then(({data}) => data.map(story => ({...story}))); // Why copy the story objects?
}
static getStoryToRead (storyName) {
return axios.get(url + storyName))
.then(({data}) => data);
}