Mongodb not storing string array in document - node.js

If I add console.log(req.body.biddingGroup) to my PUT method then
it returns
[ [ { bidderId: '5dd5b31213372b165872bf5b' } ] ]
Therefore I know that the value is being passes properly, but if I add the line biddingGroup: req.body.biddingGroup
the bid never updates to mongodb. If I remove that one line, then the bid updates.
Not sure why it's not being passed to mongodb. I also tried in monogoose model
biddingGroup: [{
type: String
}]
but that returned the error
Cast to string failed for value "{}" at path "biddingGroup"
mongoose schema
const mongoose = require('mongoose');
const postSchema
= mongoose.Schema({
title: {type: String},
startingBid: {type: String},
bidderId: {type: String},
currentBid: {type: String},
lastBidTimeStamp: {type: Date},
increments: {type: String},
shippingCost: {type: String},
auctionType: {type: String},
buyItNow: {type: String},
snipingRules: {type: String},
auctionEndDateTime: {type: String},
biddingGroup: {bidderId: {type: String}},
currentBid: { type: String, require: true },
lastBidTimeStamp: { type: Date, required: true },
creator: { type: mongoose.Schema.Types.ObjectId, ref: "User"},
});
const Auction = mongoose.model('Listing', postSchema);
module.exports = Auction;
app.js
app.put('/api/listings/:id', (req, res) => {
console.log(req.body.biddingGroup);
Post.findByIdAndUpdate({ _id: req.params.id },
{
currentBid: req.body.currentBid,
lastBidTimeStamp: Date.now(),
bidderId: req.body.bidderId,
biddingGroup: req.body.biddingGroup,
auctionEndDateTime: req.body.auctionEndDateTime
}, function (err, docs) {
if (err) res.json(err);
else {
console.log(docs)
}
});
});
I appreciate any help!

From your mongoose schema you are specifying the "biddingGroup" to be an array of strings, but what you actually get (based on your console output) is an array of arrays of objects, each of those objects then should have a property called bidderId, which is a string.
To achieve a schema that matches what you get in your console.log, you can do the following:
const postSchema = new mongoose.Schema({
...
biddingGroup: [[{bidderId: String}]],
...});

Related

How to filter documents on mongodb based on reference populated subdocuments?

I am trying to grab documents based on populated subdocuments.
Here are my models
// User model
var UserSchema = new mongoose.Schema({
username: {type: String, required: true, trim: true},
firstName: {type: String, required: true, lowercase: true},
lastName: {type: String, required: true, lowercase: true},
phone: {type: String, required: false},
email: {type: String, required: true},
password: {type: String, required: true},
blogs: {type: mongoose.Schema.Types.ObjectId, ref: 'Blogs'}
}, {timestamps: true});
// Blog Model
var BlogSchema = new mongoose.Schema({
description: String,
tags: [String],
other: [Object],
}, {timestamps: true});
This is how I am grabbing documents
fetchAllByFilter: async function(req, res) {
try {
let result = await Users.find({}).populate('blog');
return res.status(200).send(result);
} catch (err) {
return res.status(200).send({error: err});
}
},
Now my main question is, how would I grab Users based on their Blogs referenced documents?
For example, Find Users with Blogs that has Blog.tags of "food", "cars", "movies" and/or Blog.other of [{...SomeObject}, {...SomeOtherObject}]
looking at mongo docs match an array, you could make a utility function somewhat like this...
async function findByTag(tag) {
const blogIds = await Blog.find({ tags: tag }).select("_id");
const users = await User.find({
blogs: { $in: blogIds.map((blog) => blog._id) }
}).populate("blog");
}

Translate mongo nested array query into mongoose

I have the following query working with mongo, it returns the expected result
db.getCollection('trainings').find({"sections.employees.employee":ObjectId("5d3afa1a58a7160ea451d1db")})
but when I try the following call with mongoose, it returns an empty array
Training.find({'section.employees.employee': "5d3afa1a58a7160ea451d1db"})
Need some helping to translate the mongo query to mongoose.
If you need anything else just add a comment and I will post here.
It's worth mentioning that I have already tried passing a new ObjectId with the String value, but it also returns an empty array.
Edit: Query usage
return await Training.find({'section.employees.employee': "5d3afa1a58a7160ea451d1db"})
Edit: Model
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const EmployeeSection = new Schema({
employee: {type: Schema.Types.ObjectId, ref: 'Employee', required: true},
fulfilled: {type: Boolean, default: null},
});
const Section = new Schema({
order: {type: Number, required: true},
date: {type: Date},
employees: {type: [EmployeeSection]},
answers: {type: Number},
hits: {type: Number}
});
const GoalSchema = new Schema({
understanding: {type: Number, required: true},
fixation: {type: Number, required: true}
});
const Evidence = new Schema({
description: {type: String, required: true},
file: {type: String}
});
const Question = new Schema({
participants: {type: Number},
answers: {type: Number},
hits: {type: Number}
});
const TrainingSchema = new Schema({
company: {type: Schema.Types.ObjectId, ref: 'Company', required: true, index: true},
creationDate: { type: Date, default: Date.now },
title: {type: String},
obs: {type: String},
questionNumber: {type: Number},
reference: {type: String},
sections: {type: [Section]},
goals: {
answers: {type: GoalSchema, required: true},
hits: {type: GoalSchema, required: true}
},
evidences: {type: [Evidence]},
questions: {type: [Question]},
area: {type: Schema.Types.ObjectId, ref: 'TrainingArea', required: true},
});
const Training = mongoose.model('Training', TrainingSchema);
module.exports = Training;
I am willing to change the Model schema, if the problem really lays there, but didn't really want to do it.
Why its always a typo?
db.getCollection('trainings').find({"sections.employees.employee":ObjectId("5d3afa1a58a7160ea451d1db")})
Training.find({'section.employees.employee': "5d3afa1a58a7160ea451d1db"})
Forgot s on sections
Made the problem a bit easier for me.
const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/training", { useNewUrlParser: true })
const util = require("util")
const Schema = mongoose.Schema;
const EmployeeSection = new Schema({
employee: {type: Schema.Types.ObjectId, ref: 'Employee', required: true}
});
const Section = new Schema({
employees: {type: [EmployeeSection]}
});
const TrainingSchema = new Schema({
sections: {type: [Section]}
});
const Training = mongoose.model('Training', TrainingSchema);
Training.find(
{
"sections.employees.employee": mongoose.Types.ObjectId("5d3afa1a58a7160ea451d1db")
})
.exec()
.then(result => {
console.log(util.inspect(result, false, null, true /* enable colors */))
}).catch(err =>{
console.log(err)
})

How do I use nested schemas in mongoose, using 'type', to create arrays?

I am trying to create a nested mongoose schema that uses 'type' to create a nested array.
The schema that I think I am having an issue with is "chorePerson".
Here is the data that I am trying to put into a schema:
{
"chart": [
{
"ordinal": 0,
"chorePerson": [
{
"person": "emily",
"chore": "Catbox"
},
{
"person": "Steve",
"chore": "Dishes"
}
]
}
]
Here is my current schema. Note the use of "type" for "chart" and "chorePerson"
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const chorePersonSchema = new mongoose.Schema({
person: {type: String, requried: true},
chore: {type: String, required: true},
});
const chartSchema = new mongoose.Schema({
ordinal: {type: Number, required: true},
chorePerson:{ type: chorePersonSchema },
});
// create the schema
const ChoreChartSchema = new Schema({
affiliation: {type: String, required: true},
currentWeekNumber: {type: Number, required: true},
currentYear: {type: Number, required: true},
chart:{ type: chartSchema },
date: {type: Date, default: Date.now},
})
module.exports = ChoreChart = mongoose.model('cm_chorechart', ChoreChartSchema)
When I run my code this is what I get before the crash:
{ _id: 5c742ed116a095522c38ddfc,
affiliation: 'family',
currentYear: 2019,
currentWeekNumber: 9,
date: 2019-02-25T20:26:33.914Z,
chart: [ { ordinal: 0, chorePerson: [Array] } ] }
I think... chorePerson is causing the error... but I don't know how to fix it.
Here is the exception:
(node:6728) UnhandledPromiseRejectionWarning: ObjectExpectedError: Tried to set nested object field `chart` to primitive value `[object Object]` and strict mode is set to throw.
What I have tried
I tried this schema:
const chartSchema = new mongoose.Schema({
ordinal: {type: Number, required: true},
chorePerson : [{
person : String,
chore : String
}]
});
Update:
OK... so I went back to basics and this works, but it's not how I want the final schema to be. Can anybody help out with nesting this ?
// create the schema
const ChoreChartSchema = new Schema({
affiliation: {type: String, required: true},
currentWeekNumber: {type: Number, required: true},
currentYear: {type: Number, required: true},
// chart:{ type: chartSchema },
chart:[{
ordinal: 0,
chorePerson : [{
person : String,
chore : String
}]
}],
date: {type: Date, default: Date.now},
})
Turns out it was easier than I thought:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const chorePersonSchema = new mongoose.Schema({
person: {type: String, requried: true},
personID: {type: String, required: true},
chore: {type: String, required: true},
choreID: {type: String, required: true},
});
const chartSchema = new mongoose.Schema({
ordinal: {type: Number, required: true},
chorePerson : [{ type:chorePersonSchema }]
});
// create the schema
const ChoreChartSchema = new Schema({
affiliation: {type: String, required: true},
weekNumber: {type: Number, required: true},
year: {type: Number, required: true},
chart:[{type: chartSchema}],
date: {type: Date, default: Date.now},
})
module.exports = ChoreChart = mongoose.model('cm_chorechart', ChoreChartSchema)

Mongoose Populate Method is not populating value

I have two mongoose schema as following
var ServiceSubType = new Schema({
displaySubTypeName : String,
subTypeDescription : String,
status : { type: String, default: Constants.ACTIVE },
lastUpdatedOn : Date,
createdOn : { type: Date, default: Date.now }
} , { collection: 'SERVICE_SUB_TYPES' });
and
var ServiceType = new Schema({
displayName : String,
description : String,
status : { type: String, default: Constants.ACTIVE },
lastUpdatedOn : Date,
serviceSubTypeId : {type: Schema.Types.ObjectId, ref: 'ServiceSubType', index: true},
createdBy : { type: Schema.Types.ObjectId, ref: 'SystemUser', index: true },
createdOn : { type: Date, default: Date.now }
} , { collection: 'SERVICE_TYPES' });
I have populated Type Object as below
module.exports.addNewServiceType = function(serviceType_obj, callback) {
serviceType_obj.save(serviceType_obj,callback);
}
Now I am trying to populate ServiceSubType document and then at the same time trying to populate "serviceSubTypeId" of ServiceType object referenced to ServiceSubType created.
Here is my piece of code for the same purpose.
module.exports.addServiceSubType = function(serviceTypeObjId, serviceSubType_obj, callback) {
serviceSubType_obj.save(serviceSubType_obj, function (error, serviceSubType) {
});
serviceSchema.ServiceType.findById(serviceTypeObjId, function (err, serviceType) {
var opts = { path: 'serviceSubTypeId'};
serviceSchema.ServiceType.populate(serviceType, opts, function (err, user) {
console.log(serviceType);
});
}).exec(callback);
}
But it is not workign and not populating any value in Existing SubType object.
I admit my approach could be very wrong as I am very new in this technology. Appreciate any kind of help to run this piece of code as expected.
Thanks
Ajoy
I think your ref should be the same setting as the collection on the object
serviceSubTypeId : {
type: Schema.Types.ObjectId,
ref: 'SERVICE_SUB_TYPES', <==== your collection type goes here
index: true
},
Mongoose doesn't know anything about your JavaScript object types. Instead, it tracks things based on the collection name that you provide (or that it generates).
update based on comments below
I have some example code that I wrote a while back, and it looks like I'm letting Mongoose generate the collection name for me. However, I am supplying a name to the mogoose.model() call, when registering my type for a collection.
For example, I have a Post type and a User type. The Post contains an author which is a reference to the User.
It looks like this:
// post
// ----
var PostSchema = new mongoose.Schema({
date: {type: Date, required: true, default: Date.now},
title: {type: String, required: true},
content: {type: String, required: true},
author: {
type: SchemaTypes.ObjectId,
ref: "user"
},
comments: [CommentSchema]
});
var Post = mongoose.model("blog", PostSchema);
// user
// ----
var UserSchema = mongoose.Schema({
firstName: {type: String},
lastName: {type: String},
username: {type: String, required: true, index: {unique: true}},
email: {type: String, required: true},
password: {type: String, required: true},
url: {
type: mongoose.Schema.Types.ObjectId,
ref: "url"
}
});
User = mongoose.model("user", UserSchema);
In this example code, I'm setting the ref to "user" because I am registering my model as "user" down below, in the mongoose.model method call.
Are you registering your models using mongoose.model and supplying a name? if so, use that name.

about mongoose populate relation a string field

I have two Schema
1 - User
UserSchema = new db.Schema({
email: {type: String, required: true},
pass: {type: String, required: true},
nick: {type: String, required: true},
admin: {type: String, default: ''},
reg: {type: Date, default: Date.now}
});
2 - Article
ArticleSchema = new db.Schema({
title: {type: String, required: true},
alise: {type: String},
time: {type: Date, defaults: Date.now},
view: {type: Number, defaults: 0},
author: {type: String},
content: {type: String},
classes: {type: db.Schema.Types.ObjectId, ref: 'Classes'},
user: {type: String, ref: 'User'}
});
I want ArticleSchema user field relation UserSchema nick.
my code:
Model.findOne({}).populate('classes user').exec(function(err, res){
if(err){
cb(err);
}else{
cb(null, res);
}
});
This is not working
message: 'Cast to ObjectId failed for value "tudou" at path "_id"'
What should I do?
Apparently you are using Mongoose, right?
If yes, to do it you must use db.Schema.Types.ObjectId in the ArticleSchema user field. So, your ArticleSchema should looks like this:
ArticleSchema = new db.Schema({
title: {type: String, required: true},
alise: {type: String},
time: {type: Date, defaults: Date.now},
view: {type: Number, defaults: 0},
author: {type: String},
content: {type: String},
classes: {type: db.Schema.Types.ObjectId, ref: 'Classes'},
user: {type: db.Schema.Types.ObjectId, ref: 'User'}
});
According to documentation:
There are no joins in MongoDB but sometimes we still want references to documents in other collections. This is where population comes in.
So, taking a look here, we can do something like that:
//To create one user, one article and set the user whos created the article.
var user = new UserSchema({
email : 'asdf#gmail.com',
nick : 'danilo'
...
});
user.save(function(error) {
var article = new ArticleSchema({
title : 'title',
alise : 'asdf',
user : user,
...
});
article.save(function(error) {
if(error) {
console.log(error);
}
});
}
And to find an article that was created for danilo:
ArticleSchema
.find(...)
.populate({
path: 'user',
match: { nick: 'danilo'},
select: 'email nick -_id'
})
.exec()
I suggest you to read about mongoose populate here
As of 4.5.0 You can use populate virtuals : http://mongoosejs.com/docs/populate.html#populate-virtuals
UserSchema = new db.Schema({
email: {type: String, required: true},
pass: {type: String, required: true},
nick: {type: String, required: true},
admin: {type: String, default: ''},
reg: {type: Date, default: Date.now}
});
ArticleSchema = new db.Schema({
title: {type: String, required: true},
alise: {type: String},
time: {type: Date, defaults: Date.now},
view: {type: Number, defaults: 0},
author: {type: String},
content: {type: String},
classes: {type: db.Schema.Types.ObjectId, ref: 'Classes'},
user: {type: String}
});
ArticleSchema.virtual('_user', {
ref: 'User', // The model to use
localField: 'user', // Find people where `localField`
foreignField: 'email', // is equal to `foreignField`
// If `justOne` is true, 'members' will be a single doc as opposed to
// an array. `justOne` is false by default.
justOne: true,
options: { sort: { name: -1 }, limit: 5 }
});
var User = mongoose.model('User', UserSchema);
var Article = mongoose.model('Article', ArticleSchema);
Article.find({}).populate('_user').exec(function(error, articles) {
/* `articles._user` is now an array of instances of `User` */
});

Resources