How can I dynamically build a mongoose query that has an objectId? - mongodb

I'm trying to dynamically build a mongoose query. The problem I'm having is that I can't figure out how to do this when the query contains an objectId.
I'm using mongoose 5.4.6.
My mongoose schema looks something like this:
stuff: String,
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
moreStuff: String,
});
I need to dynamically build my query, and one of the possible fields to query for is user. The fields to query for are sent to the server via a params object. When the field I'm querying for is stuff, then it's easy. I just do something like the following:
let query = {};
query.stuff = params.stuff;
this.model('MyModel').find(query)...
However, I can't figure out how to search for user, because params.user is just the string version of the mongo id, but it needs to be formatted as objectId("params.user") for the query to work. That is, I need something like:
query.user = objectId("params.stuff");
How can I get this to work?

I usually do like this.
const ObjectId = require('mongodb').ObjectID
const MyModel = require('../models/mymodel')
let query = MyModel.findOne()
query.where('_id').equals(new ObjectId(params.stuff))

Related

Mongodb Ref dynamic populate with grapqhl?

I have to decide whether to populate or not according to the query request, but I don't know how to do it.
So Example
If my model User is looks like this
below syntax is from typegoose and typegraphql
class User {
#Field()
#prop()
name: string;
#Field()
#prop(ref:"House")
house: Ref<House>
}
And here is two diffent query
Query1
user {
name
}
Query2
user {
name
house {
location
}
}
And in the resolver
User: () => {
const user = UserModel.find(blahblah)**.populate("house")**
return user
}
Query1 dose not need populate
but Query2 need
in same resolver!
I want to decide whether to populate or not depending on the requirements of the query.
I can't decide whether to populate or not without knowing what is the actual query was in resolver.
I found very similar question in stackoverflow
But there is not proper answer...
Solving relationships in Mongoose and GraphQL
i dont know much about graphql, but i think there is some method to get if that path is requested, so the following should work:
let query = Model.find(basicQuery);
if (req.path) { // replace this with graphql's method to get if the path is requested
query = query.populate(yourPath);
}
const doc = await query.exec();
PS: but as an comment already noted, i think there is some better method to do this in graphql (another resolver?)

Format response from mongoose into a model

How do you go about formatting the data response from mongoose? For a simple Post Schema
const postSchema = new mongoose.Schema({
title: {
type: String,
required: true,
}
},{
timestamps: true
});
Whenever I do a GET request to find all the post, It returns me all its fields including _id and __v in which I wouldn't want to return those fields in an API.
Is there a way I would select only certain fields that I would want to return?
As far as I've found was that I could set a second parameter of title onto my query and it would return only the _id and title.
const post = await Post.find({},'title');
I find the method above isn't the proper way to filter fields in cases in the future where the values are deeply nested object and we would like to pick out certain values.
Is there perhaps a way to create a Model/Class and pick the fields based on the Model/Class and return the respond?
You can use select from mongoose.
You can either select only the fields you want.
var find = await model.find({}).select("my_field")
Or not show the fields you don't want
var find = await model.find({}).select("-my_field")
Check the documentation

Mongoose Querying Views

I'm currently using mongoose v. 5.25, against mongoDB v.3.6.
My application is supposed to query data from many different views, for instance, a view I currently have at my DB: db.joboffers_view.find()
will return many records that have been aggregated from different collections.
For a normal collection model, I query it like so:
const model = db.model(attribute);
/*where attribute, can be any registered schema */
model.find().
then((result) => {
resolve(result);
}).
catch((err) => {
reject(err);
});
Then way I register my models is something like this (simplified code):
//...
//abstracting boring connection methods
const db = mongoose.connection
//...
//simple model schema
const users_schema = {
_id: ObjectId,
another_field: String
};
//here I'm registering a schema for a VIEW, instead of normal collection
const view_schema = {
_id: ObjectId,
another_field: String
};
//...
//then
db.model('users', users_schema);
db.model('view', view_schema);
When I run a query from any of my registered models, I get the results just fine. However, when I run it against a model that represents a view on my mongo database, it returns an empty array.
No errors, no nothing, just an empty array.
I have looked through mongoose documentation, and I didn't find any specific method or pattern for querying a view, instead of a collection data.
It seems to be the same way I would do for any other collection I have in my system.
Am I missing something?
I also faced the same issue and figured out the problem is that mongoose, by default, reads collection names by pluralizing the model/view name.
So when you create any view and want to use it in mongoose, either make sure your view name is plural (add s to end of view name) or pass a collection name when initializing a schema.
Example
const users_schema = {
_id: ObjectId,
another_field: String
};
mongoose.model('vw_user_info', users_schema, 'vw_user_info');
I have same problem, but i solved it, please check the name of the view in mongodb, it must be same with db.model('view_name', view_schema);
You can open Mongoose debug by config like this mongoose.set('debug', true);
Add 3rd argument
db.model('view', view_schema, 'view_name_in_db')

Search a value in all collections of MongoDB database using Mongoose?

I am new to Mongoose. I am struck to get data in every collection in Database.
I have some collections with a field country.
Lets say company_Information is collection having country as a field.
var companyInformation = new Schema({
....
country:{type: String},
..
})
mongoose.model('company_Information',companyInformation);
similarly country field may present in some other collection.
Instead of searching a value of country in each collection using
company_Information.find({ 'country': 'India' })
someCollection.find({ 'country': 'India' })
someCollection2.find({ 'country': 'India' })
is there any way to search a record in every collection in database?
Working example would help me.
Thank you.
For example you can use something like this:
const mongoose = require('mongoose');
const findAllCountries = (country_name)=>{
let models = [];
models.push(mongoose.models.someCollection1);
...
models.push(mongoose.models.someCollectionN);
return Promise.all(models.map(model=>model.find({'country': country_name})));
}
So you can use this function like this:
findAllCountries('USA').then(result=>{
console.log(result);
}).catch(err=>{throw err;})

Mongoosejs can't query with findById

I have a meteor application saving stuff to mongodb and I have an api I wish to make and expose via REST.
express = require 'express'
mongoose = require 'mongoose'
app = express()
mongoose.connect process.env.MONGO_URL
Account = mongoose.model 'users',
profile:
available: Boolean
app.get "/accounts/meta/:account_id", (req, res) ->
account = Account.findById req.params.account_id
, (error, account) ->
if account?
res.jsonp
account: account
else
res.jsonp 404,
error: "Account not found"
app.listen 2000
The problem is that I can't query by the id's I see in my database. For example I have this user:
{
"_id": "zcdsHuKr5dTh3xHz5",
"createdAt": 1373188729653,
"last_seen": 1373465529548,
"profile": {
....
If I go to /accounts/meta/zcdsHuKr5dTh3xHz5 it says 'Cast to ObjectId failed for value "zcdsHuKr5dTh3xHz5" at path "_id"'. I tried in every possible way to query for my document without luck. Any ideas?
The problem is that you need to define a schema for your model to tell Mongoose that your _id field is a String instead of the standard ObjectId in this collection:
AccountSchema = new mongoose.Schema
_id: String
profile:
available: Boolean
Account = mongoose.model 'users', AccountSchema
Seems that your _id field isn't an ObjectId. The method findById on Mongoose expects:
id objectid, or a value that can be casted to one
So, if your _id in fact isn't an ObjectId, you should query using findOne method
account = Account.findOne { "_id" : req.params.account_id }
The currently propagated answer is not a good idea. Don't change the schema for your model to tell Mongoose that your _id field is a String. That is a bad idea in terms of validation and should be considered a hack.
Try this instead:
If you want to query for an _id in mongoose, you have to cast the _id to ObjectId
AccountSchema = new mongoose.Schema({
_id: ObjectID(),
profile: {
available: Boolean
});
Account = mongoose.model('users', AccountSchema);
Mongoosejs requires you to cast the id in the query as well (I didn't find anything about this in the mongoose documentation either):
account = Account.findOne({ "_id" : mongoose.Types.ObjectId(req.params.account_id) });