How can i use an if statement in a mongoose query? - node.js

i have a mongodb collection named Feed and it has an attribute named "type". according to that string, i want to send a changeable fields with json. For example if type is "photo" i want to do somethig like that
schema.find({number: "123456"},"body number",
function(err, data) {
but if the string is story, instead of photo; İn the same 'schema.find' query,it should create a json with "body url" instead of "body number". and they all should be passed with the same json.
res.json(data);
For a clear example, i want my json to be like this. as you se the fields change according to "type". but they are all actually in the same collection.
[
{
type: 'photo',
number: 123456,
url: 'asd.jpg',
},
{
type: 'story',
body: 'hello',
number: 123456,
}
]

So basically you want to return certain documents fields from the Feed collection, which are specified in a variable like e.g. "firstName pic points photos".
Are there Feed documents with the story field?
The Model.find() does not create any schema.
Maybe edit with further code so we can understand the command.

For document-specific JSON formatting like this, you can override the default toJSON method of your Feed model as shown in this gist.
UPDATE
If you want this sort of flexibility in your documents then it's even easier. Just define your schema to include all possible fields and then only set the fields that apply to given document for its type. The fields that you don't use won't appear in the document (or in the JSON response). So your schema would look like:
var feedSchema = new Schema({
type: { type: 'String' },
venue: Number,
url: String,
body: String
});

Take a look to mongoose-schema-extend. Using the 'Discriminator Key' feature, you can instruct .find() to create the proper model in each individual case.
Your code should look like this (not tested):
var feedSchema = new Schema({
venue: Number,
}, {discriminatorKey : 'type' }});
var photoSchema = feedSchema.extend({
url: String
});
var storySchema = feedSchema.extend({
body: String
});
var Feed= mongoose.model('feed', feedSchema );
var Photo= mongoose.model('photo', photoSchema );
var Story= mongoose.model('story', storySchema );
//'photo' and 'story' will be the values for 'type' key
Feed.find({venue: "123456"}, function(err, models) {
console.log(models[0] instanceof Photo); // true
console.log(models[0] instanceof Story); // false
console.log(models[1] instanceof Photo); // false
console.log(models[1] instanceof Story); // true
});

Related

mongodb query events done to an item and group them into an array

I know that the title might be a bit vague, but I will elaborate here.
basically what I am trying to achieve is the following:
I have a collection with documents that have the following scheme:
bookId: <uuid>
genre: <string>
isTaken: true
historyIndex: each time something happens i increment this
returnedAt: not required but will be present on documents with historyIndex
takenAt: not required but will be present on documents with historyIndex
there are documents with no historyIndex field because they are representing the book itself without the action that were done to the book.
what i want to do is this:
I want to query the books by their unique uuid and then use the documents with historyIndex and add them to the main documents as in an array as called bookEvents
so the final results will be
bookId:
bookEvents: [] --> an array with all the entries that contain history index
basically everytime the status of the book changes, i am inserting an event with the date it was taken on and the date it was returned on
What would be the best way of achieving such thing ?
Should I query once and iterate in my code ?
Should I query twice (once where the fields exist and once where they don't) ?
Thank you in advance for all the people that will try to help!
You can use the plugin or events to achieve this.
var CounterSchema = new mongoose.Schema({
_id: {type: String, required: true},
seq: { type: Number, default: 0 }
});
var counter = mongoose.model('counter', CounterSchema);
var entitySchema = mongoose.Schema({
sort: {type: String}
});
entitySchema.pre('save', function(next) {
var doc = this;
counter.findByIdAndUpdateAsync({_id: 'entityId'}, {$inc: { seq: 1} }, {new: true, upsert: true}).then(function(count) {
console.log("...count: "+JSON.stringify(count));
doc.sort = count.seq;
next();
})
.catch(function(error) {
console.error("counter error-> : "+error);
throw error;
});
});
refer https://stackoverflow.com/a/40137723/8201020

Save entity with id created in code, mongoose

How can I do to pass the id of a document from outside and not that mongoose generates it?
I need the objects to be stored with the id I tell them, but mongoose overwrites it and saves it with the one he wants. I tried several ways now and nothing happens.
It is an entity that I am distributing through events in several databases, so I need it to be stored with the id I want to maintain the integrity of the data.
Now I have this and it says "document must have an _id before saving", but the id I have already put it, does not recognize it.
The scheme is like this:
const schema = new Schema({
_id: { type: String },
name : { type: String },
});
I also tried with this, and the error is the same:
const schema = new Schema({
_id: { type : String },
name : { type: String },
},
{
_id: false
});
I am passing the object like this:
Item.create({ _id: 'my uuid here', name: 'something' });
but when it is saved it remains with the id generated by mongoose replacing mine, that is, it changes it to me with a _id: '5twt563e3j5i34knrwnt43w'
Your syntax should work, but sometimes mongoose acts weird.
You can try this syntax (works on my project) :
const item = new Item({ name: 'something' });
item._id = 'my uuid here';
await item.save();
Instead of using a random uuid, you need to use a mongoDB objectID. Mongoose can also create that,
var mongoose = require('mongoose');
var id = mongoose.Types.ObjectId();
Store this id in the collection,
Item.create({ _id: id, name: 'something' });

NodeJS + MongoDB mapping relational data in toJSON()

I have three models (collections): Project, User and Category.
The Project Schema looks like this:
var ProjectSchema = new mongoose.Schema({
title: { // title of the project
type: String
},
_category : {
type: mongoose.Schema.Types.ObjectId
},
participants: [
{
_user: {
type: mongoose.Schema.Types.ObjectId
},
invitedDate: {
type: Date
}
]
}
The User model has the usual properties: name, email, (hashed) password, address etc.
The Category model has the properties: name, description.
What is an efficient way to retrieve certain properties from User and Category inside the toJSON method of the Project model?
So, for example, when I GET the projects, I don't want the response to return the ObjectID but rather the name and email address of the User, and the name and description of the Category.
You can override toJson method and delete properties which you dont want to return.
Lets take this example. If you dont want to return userId then delete it from definition of toJson method
UserSchema.methods.toJSON = function() {
var obj = this.toObject()
delete obj.userId
return obj
}
Just like this, you can change for any schema.

How to update a specific object in a array of objects in Node.js and Mongoose

I am new to node.js coming from java experience. I have a situation that I am trying to wrap my head around. My stack is express.js, mongoose, ejs template. Here is my scenario:
I have a schema:
var UserSchema = mongoose.Schema({
name: {
type: String,
index: true
},
password: {
type: String,
select: false
},
email: {
type: String
},
academic: [{
qualification: String,
institute: String,
from: String,
to: String,
about: String
}]
});
there is a list of academics. I want to update only one academic object in that list. How would I go about this?
router.post('/academic/schools/update', function (req, res) {
});
I pass the values from ejs template into the route and getting the values in the req.body. How would I in node and mongoose query that specific object in the route and then updates its values. I have thought about maybe adding an Id to the academic object to be able to keep track of which to update.
Each academic sub document will have an _id after you save.
There are two ways you can do it. If you pass the id of the user and id of the academic sub-doc id in the url or request body, then you can update like this:
User.findById(userId).then(user => {
let academic = user.academic.id(academicId);
academic.qualification = 'something';
return user.save();
});
If you only pass the id of the academic sub-doc, then you can do it like this:
User.findOne({'academic._id': academicId}).then(user => {
let academic = user.academic.id(academicId);
academic.qualification = 'something';
return user.save();
});
Note that sub document array return from mongoose are mongoosearray instead of the native array data type. So you can manipulate them using .id .push .pop .remove method http://mongoosejs.com/docs/subdocs.html

How to remove mongo specific fields from result (NodeJS, Mongoose)

I want to remove all Mongo specific fields (like '_id') from query result. Is there a simple method to do this or should I remove fields manually? If yes, then which are that fields and how to do that?
I'm using NodeJS and Mongoose
You can use select() method for remove the field from your query:
Model.find({}).select("-removed_field").then (resp => {
// your code
});
You should specified the "-" before field name, to be remove this field.
If you want remove several fields - you can specified their as array:
Model.find({}).select(["-removed_field1", "-removed_field2" ... ]).then (resp => {
// your code
});
Also you can to select only specified fields, using this method without "-"
Model.find({}).select(["field1", "field2" ... ]).then (resp => {
// your code
});
If you want hide _id property you can use text argument with prefix - which will exclude this or that field from the result, for get sepecifict fields you should pass like this:
Entity.find({ ... }, 'field1 field2', function(err, entity) {
console.log(entity); // { field1: '...', field2: '...' }
});
You can specify a field to be excluded from results by using the optional 2nd parameter projection string of the find method:
Model.find({}, "-a -b").then (res => {
// objects in the res array will all have the
// 'a' and 'b' fields excluded.
});
https://mongoosejs.com/docs/api.html#model_Model.find (see projection)
you can use mongoose instance method two show specific fields from all documents
const userSchema = new mongoose.Schema({
email: {
type: String,
},
name: {
type: String,
maxlength: 128,
index: true,
trim: true,
},
});
userSchema.method({
transform() {
const transformed = {};
const fields = ['name', 'email'];
fields.forEach((field) => {
transformed[field] = this[field];
});
return transformed;
},
});
module.exports = mongoose.model('User', userSchema);
if You want to remove any specific fields like _id, You can try in two ways:
Suppose Here you try to find a user using User Model
User.find({ email: email }, { _id: 0 });
OR
const user = User.find({ email: email });
delete user._doc._id;
OP mentioned "from result", as far as I understood, it means, removing from the query result i.e. query result will contain the field, but will be removed from the query result.
A SO answer here mentions, that to modify a query result (which are immutable), we've to convert the result to Object using toObject() method (making it mutable).
To remove a field from a query result,
let immutableQueryResult = await Col.findById(idToBeSearched)
let mutableQueryResult = immutableQueryResult.toObject()
delete mutableQueryResult.fieldToBeRemoved
console.log(mutableQueryResult)
Another way of getting the mutable result is using the _doc property of the result:
let immutableQueryResult = await Col.findById(idToBeSearched)
let mutableQueryResult = immutableQueryResult._doc // _doc property holds the mutable object
delete mutableQueryResult.fieldToBeRemoved
console.log(mutableQueryResult)

Resources