I'm building a buildQuery to get posts for a social feed.
When users make a post, their university is saved in the post as university. They can also choose to make sure that ONLY other students from their same university can see it.
If they want to do so, then uniOnly is set to true on the post model.
Here's part of the PostSchema:
const PostSchema = new Schema({
university: {
type: String,
required: true
},
uniOnly: {
type: Boolean,
required: true
}
});
In the buildQuery below, the university, uni of the user, (stored in their profile document) requesting the feed is passed in as an parameter.
So what I'm trying to do is check that IF uniOnly is set to true on the post and the uni coming in is NOT the same as university on the post, then it should NOT be seen in the feed.
How can I do this? Should I be using $where? Or an if statement some
how?:
const buildQuery = (criteria) => {
const { uni } = criteria;
const query = {};
// Should I be using $where?
query.uniOnly = { $where: }
return query;
};
The buildQuery is quite large so I've cut it down to what is relevant.
Thank you
If you want to query for posts where uniOnly = false OR university = criteria.uni, then you can use $or to combine the terms logically:
const buildQuery = (criteria) => {
const query = { $or: [ {uniOnly: false}, {university: criteria.uni} ] };
return query;
};
Related
This question already has answers here:
mongodb/mongoose findMany - find all documents with IDs listed in array
(9 answers)
Closed 3 months ago.
I am trying to search using node.js, ejs and mongoose. All the filter parameters are working perfectly but only categoryIds is not (stored as a collection of ObjectIDs in the mongodb document, referring to the respective document in categories collection), always giving me the empty record set.
For example:
If I need to find the a movie called Cosmos (see the attached screenshot) then I can easily find it with all or any filter except categories. Once I select any category, the record-set will go blank even if the I have selected the one which it belongs to.
model.js
const Model = mongoose.model('Movie', new Schema({
...
categoryIds: [{
type: Schema.Types.ObjectId,
trim: true,
default: null,
ref: 'Category',
}],
copyrightId: {
type: Schema.Types.ObjectId,
trim: true,
default: null,
ref: 'Copyright',
},
...
}, {
timestamps: true
});
Controller.js
Router.get('/', (req, res) => {
const search = req.query;
const conditions = (() => {
let object = {};
['releaseYear', 'languageId', 'copyrightId'].forEach(filter => {
if (search[filter] != '') {
object[filter] = search[filter];
}
});
if (typeof search.categoryIds !== 'undefined') {
object.categoryIds = [];
search.categoryIds.forEach(item => object.categoryIds.push(item));
}
if (search.keywords != '') {
object.title = {
$regex: search.keywords,
$options: 'i'
};
}
return object;
})();
const count = await Model.count(conditions);
const items = await Model.find(conditions, {
__v: false,
imdb: false,
trailer: false,
createdAt: false,
updatedAt: false,
}).sort({
status: -1,
releaseYear: -1,
title: 1
})
.populate('languageId', ['title'])
.populate('copyrightId', ['title'])
.populate('categoryIds', ['title'])
.skip(serialNumber)
.limit(perPage);
...
});
All the fields in the search form
{
categoryIds: [
'6332a8a2a336e8dd78e3fe30',
'6332a899a336e8dd78e3fe2e',
'6332a87ba336e8dd78e3fe2c',
'634574ab339b1a6b09c1e144'
],
languageId: '',
copyrightId: '',
releaseYear: '',
rating: '',
seen: '',
status: '',
keywords: '',
submit: 'search' // button
}
filtered search parameters
{
categoryIds: [
'6332a8a2a336e8dd78e3fe30',
'6332a899a336e8dd78e3fe2e',
'6332a87ba336e8dd78e3fe2c',
'634574ab339b1a6b09c1e144'
]
}
Here is the screenshot of mongodb document.
...
if (typeof search.categoryIds !== 'undefined') {
object.categoryIds = {
$in: []
};
search.categoryIds.forEach(item => object.categoryIds.$in.push(
mongoose.Types.ObjectId(item))
);
}
console.log(object);
return object;
The is the final filter object
{
categoryIds: {
'$in': [
new ObjectId("6332a87ba336e8dd78e3fe2c"),
new ObjectId("634669f4a2725131e80d99f1")
]
}
}
Now, all the filters are working perfectly.
Thank you everyone.
The filter should contain all categoryIds and in the same order to match the document. It's not quite clear from the question if it is the intended functionality. If not, most popular usecases are documented at https://www.mongodb.com/docs/manual/tutorial/query-arrays/
I don't recall how mongoose handles types when you query with array function like $all, so you may need to convert string IDs to ObjectIDs manually, e.g.:
search.categoryIds.forEach(item => object.categoryIds.push(
mongoose.Types.ObjectId(item))
);
I'm trying to build a platform where each user is able to add games to their library, under either the "owned" or "wanted" categories, and then it is the platform's responsibility to find possible trade options.
For example, if user A has game A in their owned list, and user B wants game A, and owns games C and D, then user A will see games C and D under their possible trade options, in return for game A.
Currently, I've implemented this somewhat crudely using too many nested DB queries and I feel like there's a faster way to do this.
The following is what happens every time a user wants to see all of their trade options.
let foundUser = await User.findById({_id: req.session.user_id})
let gamesList = []
//for each game in the users have library, search it up in the game DB and add wantedBy users to an array
for (let i = 0; i < foundUser.library.have.length; i++){
let foundGame = await Game.findById({_id: foundUser.library.have[i].gameID})
//for this game, add each user in the WantedBy List to a local array
for (let j = 0; j < foundGame.wantedBy.length; j++){
//for each of these users, use their have list to build the trade object
let newFoundUser = await User.findById({_id: foundGame.wantedBy[j]})
//check if the other user wants the game for the same platform as foundUser.library.have[i].platform
console.log(newFoundUser)
console.log(foundGame.wantedBy)
let platformMatch = newFoundUser.library.want.find(game => (game.platform === foundUser.library.have[i].platform) && (game.gameID == foundUser.library.have[i].gameID))
if (platformMatch){
for (let k = 0; k < newFoundUser.library.have.length; k++){
//for each of these games in the other users have list, make a trade object
let newFoundGame = await Game.findById({_id: newFoundUser.library.have[k].gameID})
let tradeObject = {
gameOffered: newFoundUser.library.have[k].gameID,
gameOfferedBackImg: newFoundGame.backImg,
gameOfferedPlatform: newFoundUser.library.have[k].platform,
gameOfferedTitle: newFoundGame.title,
inReturnForTitle: foundGame.title,
inReturnForPlatform: foundUser.library.have[i].platform,
inReturnFor: foundGame._id,
otherUserID: newFoundUser._id
}
gamesList.push(tradeObject)
}
}
}
}
res.render('trade', {gamesList: gamesList, mainUser: foundUser._id})
The nested loops and DB queries make this really slow, especially if the no. of users and the no. games in their library increases.
The following are the DB schemas:
The User Schema:
username: {
type: String,
required: ['true', 'Username cannot be blank'],
},
email: {
type: String,
required: ['true', 'Email cannot be blank']
},
password: {
type: String,
required: ['true', 'Password cannot be blank'],
},
phoneNum: {
type: String,
required: true,
unique: true
},
isVerified: false,
address: {
city: String,
area: String,
street: String,
nearestLandmark: String
},
verificationCode: String,
library: {
have: [{
gameID: String,
platform: String
}],
want: [{
gameID: String,
platform: String
}]
},
notifications: [
{
dateTime: Date,
message: String
}
]
})
The Game Schema:
const gameSchema = new mongoose.Schema({
title: String,
backImg: String,
wantedBy: [String]
})
Any help optimising this would be greatly appreciated. Thank you!
Hi sorry for the confusing question. Basically, I want to find all the users that have emails that are included in the array.
For example I have an array:
const arr = ['test#gmail.com', 'test2#gmail.com']
and I have my model
model User {
id Int
username String
name String
email String
}
I want to do something like
const data = await prisma.user.findMany({
where : {
email: in arr
},
select : {
id: true
}
});
I have been trying to find a workaround for this for the longest time.
This is the syntax for the in operator in Prisma.
const arr = ['test#gmail.com', 'test2#gmail.com']
const data = await prisma.user.findMany({
where : {
email: {in: arr}
},
select : {
id: true
}
});
You can read more in the Prima Client Reference in the docs.
I'm trying to create a document in my Schema that essentially works like a dictionary with an array of values (dates):
I want to use this to keep track of email correspondence I am sending users:
let d = {
'generic-contact' = ['11/02/2019', '11/05/2020'],
'update-profile' = ['1/01/2018']
}
I would then update this document field with something like:
let emailAddresses = ['joebloggs#yahoo.com', 'foobar#googlemail.com']
let recipients = await Profile.find({ email: { "$in" : emailAddresses } })
let emailTopic = 'newsletter03'
recipients.forEach(user => {
user.correspondenceHistory[emailTopic].push(Date.now())
user.save()
})
I want to do this so that I make sure that I don't send the same user the same email within a certain period of time.
However I can't work out how to set this up in my schema. Is this sort of structure possible?
I've tried many different structures for correspondenceHistory, but none of them have worked and I can't work out what I'm doing wrong. Here is my schema as it stands:
const mongoose = require("mongoose");
const passportLocalMongoose = require("passport-local-mongoose");
var profileSchema = new mongoose.Schema({
email: String,
firstname: String,
lastname: String,
correspondenceHistory: { type: Array } ### Here ###
}, { discriminatorKey: 'accountType', retainKeyOrder: true, timestamps: true });
I have two Schema for user & todo. Every todo has an owner as a user, every user has an array of todos.
// user.js
const TodoSchema = require('./todo').TodoSchema;
var UserSchema = mongoose.Schema({
name: {
type: String,
required: true
},
todos: {
type: [TodoSchema]
}
});
module.exports.UserSchema = UserSchema;
module.exports.UserModel = mongoose.model('UserModel', UserSchema);
// todo.js
var TodoSchema = mongoose.Schema({
body: {
type: String, required: true
},
owner: {
type: mongoose.Schema.Types.ObjectId,
ref: 'UserModel',
required: true
}
});
module.exports.TodoSchema = TodoSchema;
module.exports.TodoModel = mongoose.model('TodoModel', TodoSchema);
I entered data like this.
var nUser = new UserModel({
name: "Alex
)};
nUser.save().then(user => {
var t = new TodoModel({
body: "my new todo",
owner: user._id
});
t.save().then();
});
But the problem is I want to get all the todos from a specific user, something like this...What is the correct way?
UserModel.findOne({name: "Alex"})
.then(user => {
// user.todos
});
P.S.
I can do this like TodoModel.find({owner: specific_user._id}), but I want it from UserModel.
Since you're asking for the proper way of doing it, I am gonna start with your User Schema. If you want to find all the todos of a user, then putting the todo documents inside an array in the User document is not required. So you should probably remove that from your schema.
After that you can use a simple aggregation to get your desired outcome.
UserModel.aggregate([
{
$match:{
name:"Alex"
}
},
{
$lookup:{
from:"todomodels",
localField:"$_id",
foreignField:"$owner",
as:"todos"
}
}
])
this will return all the todos for that user in an array of the same name.