Mongoose findOne returns empty array field - node.js

I have a simple embedded document:
{
"username":"user001",
"name":"John",
"tasks":[
{
"id":0,
"title":"Candy",
"description":"Lots of candy for you",
"category":"food",
"cost":2500,
"candyTypes":[
{"name":"gum", "type":"sweet", "price":"2"},
{"name":"chocolate", "type":"tasty", "price":"3"}
]
}
]
}
When I try to query the task data through the mongo shell, I get everything:
db.users.findOne({ 'username': 'user001', 'tasks.id':4 }, {'tasks.$':1})
/* returns */
"tasks":[
{
"id":0,
"title":"Candy",
"description":"Lots of candy for you",
"category":"food",
"cost":2500,
"candyTypes":[
{"name":"gum", "type":"sweet", "price":"2"},
{"name":"chocolate", "type":"tasty", "price":"3"}
]
}
]
But when I try to do the same in mongoose, the candyTypes array comes back empty:
Users.findOne({ 'username': username, 'tasks.id':taskId }, {'tasks.$':1}, function (err, data) {
console.log(data);
});
/* returns */
"tasks":[
{
"id":0,
"title":"Candy",
"description":"Lots of candy for you",
"category":"food",
"cost":2500,
"candyTypes":[]
}
]
I'm pretty new to MongoDB and Mongoose, but after searching and looking through documentation, I can't figure out what I'm missing.
UPDATE
I couple users requested it, so here is my mongoose schema:
var UserSchema = new mongoose.Schema({
username:String,
name:String,
tasks:[{
id: Number,
title: String,
description:String,
category: String,
cost: Number,
candyTypes:[{
title:String,
type:String,
value:String
}]
}]
});

With Mongoose, you have to populate candyTypes array:
Users.findOne({ 'username': username, 'tasks.id':taskId }, {'tasks.$':1})
.populate('candyTypes')
.exec(function (err, data) {
console.log(data);
});
See docs: http://mongoosejs.com/docs/populate.html

I think it's related to you declaring a field called type which also has a special meaning in Mongoose, namely to signify the type of a field.
If you rename that field to something else (candyType), it'll probably work better.
Alternatively, you can use the typeKey option to make Mongoose use a different property name to signify field type.
As an aside, your document contains a field price but your schema names it value.

Related

Using Mongoose to query an array of objects

I've got a MongoDB database collection called Dealers structured a bit like this:
{
... dealer info goes here like address etc,
"user_logins": [
{
"Username": "something",
... other stuff
}
]
},{
... next dealer etc...
I'm using Mongoose to try and query on the user_logins.Username using this:
Mongoose model
const myTest = mongoose.Schema({
Username: {
type: "String",
required: true
}
}, { collection: "Dealers" })
module.exports = mongoose.model("Dealer", myTest);
The query
Dealer.find({'user_logins.Username' : 'something'}, (err, result) => {
if (err) {
console.log(err);
} else {
res.json(result);
}
});
All the Username's are distinct. But instead of returning the one matching document, it seems to be returning the whole Dealers collection.
I followed this example.
https://kb.objectrocket.com/mongo-db/use-mongoose-to-find-in-an-array-of-objects-1206
What am I doing wrong please?
Thanks.
EDIT: It seems fine if I try to find something on the root level. EG. Company name, address etc. But if I try to query an imbedded array of objects, that's when it pulls the whole collection. I don't get it.
Found the answer.
My model was wrong. It needed to reflect the actual structure of my data, which does kind of make sense.
This worked:
const myTest = mongoose.Schema({
user_logins: [{
Username: {
type: "String",
required: true
}
}]
}, { collection: "Dealers" })
module.exports = mongoose.model("Dealer", myTest);

$push into deeply nested array mongoose

my userSchema is as follows...
const userSchema = new mongoose.Schema({
firstName: { type: String },
lastName: { type: String },
movies: [
{
name: String,
duration: Number,
actors: [{ name: String, age: Number }]
}
],
});
In my NodeJS app with express I am trying to update my actors array to have another actor with value stroking from req.body.
I thought that I could do something like this...
await User.updateOne(
{
_id: req.user.id
movies._id: req.params.id
},
{
$push: { 'movies.actors': req.body }
}
)
I thought this would push an actor into the specified movie req.params.id but does nothing instead.
Try using positional operator $ in this way:
db.collection.update({
"_id": 1,
"movies._id": 1
},
{
"$push": {
"movies.$.actors": req.body
}
})
Note the only diference is the use of $. But with positional operator you are saying mongo where push the new data.
As docs says:
The positional $ operator identifies an element in an array to update without explicitly specifying the position of the element in the array.
So you can update the element movies.actors pushing new data without knowin the position of the element.
Example here
Try this:
await user.updateOne(
{$and:[{_id: req.user.id},{movie.name: 'I am Legend'}]},
{$set: { movies.actors:req.body}},
);

Can't push items in mongo array

I can't push items into MongoDB array every time that i try to push a new element it creates an empty object and i cant figure out why,
I already used the
Collection.Array.push({element})&
Collection.save()
but i cant figure out a solution
This is My Schema
const Schema = mongoose.Schema;
var ParticipantSchema = new Schema({
nom:{Type:String},
prenom:{Type:String},
email:{Type:String}
})
var CompetitionSchema = new Schema({
nom:String,
date:Date,
place:String,
participant :[ParticipantSchema]
})
module.exports = mongoose.model("Competition",CompetitionSchema);
This is my funtion
exports.addParticipant=function(req,res){
var newParticipant={
"nom":req.body.nom,
"prenom":req.body.prenom,
"email":req.body.email
}
Competition.updateOne(
{ _id:req.body.id},
{ $push: { participant: newParticipant } },
(err,done)=>{
return res.json(done)
}
);
}
the result is always an empty object like below
{
"_id": "5ded0eeb85daa100dc5e57bf",
"nom": "Final",
"date": "2019-01-01T23:00:00.000Z",
"place": "Sousse",
"participant": [
{
"_id": "5ded0eeb85daa100dc5e57c0"
},
{
"_id": "5dee3c1b08474e27ac70672e"
}
],
"__v": 0
}
There is no problem in your code, the only problem is that in schema definition you have Type, but it must be type.
If you update your ParticipantSchema like this, it will work:
var ParticipantSchema = new Schema({
nom: { type: String },
prenom: { type: String },
email: { type: String }
});
You are using another Schema in the Array. This results in so-called subdocuments (https://mongoosejs.com/docs/subdocs.html). Mongoose does not populate subdocuments by default. So all you see is just the _id. You can use the populate method to see all subdocuments in detail. ( https://mongoosejs.com/docs/populate.html ) .
Example :
Competition.
find({}).
populate('participant').
exec(function (err, comps) {
//
});
You can either use populate on the Model or on the Document. For populating a document, take a look at https://mongoosejs.com/docs/api.html#document_Document-populate . There is also a auto-populate plugin available via npm but in most cases it's not necessary : https://www.npmjs.com/package/mongoose-autopopulate .

Don't know how to write complex Mongoose query

Here is the schema used to display current tournaments in one country:
var TournamentSchema = new mongoose.Schema({
name: String,
location: String,
googlelink: String,
description: String,
format: String,
date: Date
closedate:Date
type:String
});
The webpage also has filters like in ecommerce sites. If suppose I get one query from url like:
https://www.example.com/format=5v5%7v7&&location=hyd&&ahmedabad
I need to make query for tournaments which are 5v5 or 7v7 format and which are in Hyd and Ahmedabad.
I need to write generalised query as I don't know about number of places and format.
I don't know how to do this. Can someone help me out?
Here is an example of a query I wrote that uses mongoose $or.
Event.find( { $or: [{ joiners: req.user._id }, { creator: req.user._id}] } )
.populate('creator')
.exec(function(err, goevent){
if(err){
console.log(err)
} else {
res.json(goevent)
}
})
Basically in your query param {} you can pass in something like this:
{ $or: [ { query: one}, {query: two} ] }
Like so:
Model.find({ $or: [ { query: one}, {query: two} ] }, function(err, data){
//err & success handlers
}
Once you figure that out, you can use a bunch of other logical operators as well, like $and.
if the object you are querying is nested you just do 'some.property' (use string syntax when accessing objects with dot notation)

Mongoose updating sub document array's individual element(document)

Schema of group and member are as below:
var group=new Schema({
group_id:Number,
group_name:String,
members:[member]
});
var member=new Schema({
member_id:number,
name:String,
});
Sample document after inserting some record in group collection
[{
_id:55ff7fca8d3f6607114dc57d
group_id:1001,
group_name:"tango mike",
members:[
{
_id:44ff7fca8d3f6607114dc21c
member_id:2001,
member_name:"Bob martin" ,
address:String,
sex:String
},
{
_id:22ff7fca8d3f6607114dc22d
member_id:2002,
member_name:"Marry",
address:String,
sex:String
},
{
_id:44ff7fca8d3f6607114dc23e
member_id:2003,
member_name:"Alice" ,
address:String,
sex:String
}
]
}]
My problem:
I am trying to update record of individual group member(element of subdocument members). While updating I have follwing data group: _id, group_id, members:_id and newdata. I am trying like this; but it is not working
var newData={
member_name:"Alice goda" ,
address:"xyz",
sex:"F"
}
groupModel.findOne({"_id":"55fdbaa7457aa1b9bd7f7cf7","group_id":1001},'members -_id',function(err,groupMembers){
if(err)
{
res.json({
"isError":true,
"error":{
"status":1042,
"message":err
}
});
}
else
{
var mem=groupMembers.id("44ff7fca8d3f6607114dc23e");
mem.member_name=newData.member_name;
mem.address=newData.address;
mem.sex=newData.sex;
mem.save(function(err,data){
if(!err)
//sucessfull updated
});
res.json(groupDetails);
}
});
As I understand from your question details, you would like to update one object from the members array, in accordance with the criteria that you specify.
Thus, in order to accurately run the update query for your use case, you could run the following update operation against your collection:
db.collection.update({ _id: "55ff7fca8d3f6607114dc57d",
group_id:1001,
members: {
$elemMatch: { _id: "44ff7fca8d3f6607114dc23e" }
}
},
{ $set: {
"members.$.member_name": "Alice goda",
"members.$.address": "xyz",
"members.$.sex": "F"
}});
Still, be aware that the $ positional operator only updates the first array item that matches your query.
Unfortunately, there is no possibility of updating all the array elements that match your criteria in a single operation. As you can see on MongoDB Jira, the aforementioned feature is one of the most requested functionality, but it has not yet been directly implemented in MongoDB.

Resources