Mongoose find() returning array empty - mongodb

I have the following product model:
'use strict';
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
// create a schema
let produtoSchema = new Schema(
{
descricao: { type: String, required: true },
gateways: [ { type : mongoose.Types.ObjectId, ref: 'Gateway' } ]
}
);
mongoose.model('Produto', produtoSchema);
The the following collection:
rs0:PRIMARY> db.produtos.find().pretty()
{
"_id" : ObjectId("55fef1a3d7c6912033f2da72"),
"descricao" : "Product description",
"gateways" : [
ObjectId("55fee8a97cb7db7740acb322")
]
}
rs0:PRIMARY>
So, I'm trying to use Mongoose to fetch a specific product, but 'gateway' array is empty :
let Produto = mongoose.model('Produto');
Produto.find(
{
_id: mongoose.Types.ObjectId("55fef1a3d7c6912033f2da72")
}, function(err, result)
{
if (err) console.log(err);
console.log(result);
});
And the result is :
[ { _id: 55fef1a3d7c6912033f2da72,
descricao: 'Product description',
gateways: [] } ]
A also tried, but with the same result:
Produto
.find( { _id: mongoose.Types.ObjectId("55fef1a3d7c6912033f2da72") })
.populate('gateways')
.exec(function(err, result)
{
if (err) console.log(err);
console.log(result);
});
Any idea of what I'm doing wrong ?
Thanks.

I've found the problem.
I've changed:
gateways: [ { type : mongoose.Types.ObjectId, ref: 'Gateway' } ]
by
gateways: [ { type : mongoose.Schema.ObjectId, ref: 'Gateway' } ]
What's the difference between them ?

Related

How to update with mongoose

I have this record
{
"_id" : ObjectId("5dfdff479ad032cbbc673507"),
"selection" : [
{
"highlights" : "test",
"comment" : "CHANGE THIS",
"el" : "body:nth-child(2)>div:nth-child(2)#root>div.App>p:nth-child(1)"
},
{
"highlights" : "Barrett’s lyrical prose opens with a clever and tender solution",
"comment" : "",
"el" : "body:nth-child(2)>div:nth-child(2)#root>div.App>p:nth-child(2)"
}
],
"category" : [],
"status" : "",
"url" : "http://localhost:3000/theone",
"title" : "React App test",
"__v" : 4
}
And I want to update the comment. I have tried to use update and findOneAndUpdate and nothing is working. Here is my attempt
WebHighlight.findOneAndUpdate(
{
_id: req.params.highlight,
"selection.highlights": "test"
},
{ "selection.$.comment": "yourValue" }
);
That req.params.highlight is the id (I even hardcoded it)
I also tried this
WebHighlight.findById(req.params.highlight, (err, book) => {
var test = [...book.selection];
test[0].comment = "somethibf"
book.save();
res.json(book);
});
And nothing is working.
This is the model
const webhighlightsModel = new Schema({
selection: { type: Array, default: "" },
category: { type: Array, default: [] },
title: { type: String },
url: { type: String },
status: { type: String, default: "" }
});
Actually your code seems to work, but findOneAndUpdate returns the old document if you don't give {new: true} option.
I think for this reason, you think the update wasn't successfull, but if you check your collection, you will see the update.
WebHighlight.findOneAndUpdate(
{
_id: req.params.highlight,
"selection.highlights": "test"
},
{ "selection.$.comment": "yourValue" },
{ new: true }
)
.then(doc => res.send(doc))
.catch(err => res.status(500).send(err));
Also I think it would be better if selection had a sub schema like this:
const mongoose = require("mongoose");
const schema = new mongoose.Schema({
selection: [
new mongoose.Schema({
highlights: String,
comment: String,
el: String
})
],
category: { type: Array, default: [] },
title: { type: String },
url: { type: String },
status: { type: String, default: "" }
});
module.exports = mongoose.model("WebHighlight", schema);
So with this every selection would an _id field, and it would be better to update with this _id.
You should use the $set operator to update existing values:
WebHighlight.findOneAndUpdate(
{
_id: req.params.highlight,
"selection.highlights": "test"
},
{ '$set': { "selection.$.comment": "yourValue" } }
);

I am getting error in graphql while making query for specific id

schema:
const UserType = new GraphQLObjectType({
name: 'User',
fields: () => ({
id : { type: GraphQLID },
name : { type: GraphQLString },
email : { type: GraphQLString },
})
})
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
user: {
type: UserType,
args: {
id: { type: GraphQLID }
},
resolve(parent, args){
return User.findById(args.id);
}
}
}
})
module.exports = new GraphQLSchema({
query: RootQuery
});
Here i am fetching data by id from mongodb.
I am using mongoose for mongodb client.
I have setup server with express and graphql.
and i am making below query to get result by specifi id
{
user(id: 2){
name
}
}
But, i am getting below error while making query.
{
"errors": [
{
"message": "Cast to ObjectId failed for value \"2\" at path \"_id\" for model \"User\"",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"user"
]
}
],
"data": {
"user": null
}
}
my id in database is just a integer value like below
{
"_id" : ObjectId("5d49c6dc54f1cec013ee6b49"),
"id" : 10,
"name" : "Clementina DuBuque",
"email" : "Rey.Padberg#karina.biz",
}
Please have a look.
type: UserType this should be type: new GraphQLList(UserType),

Complex query mongoose - embedded documents array

I want to execute a query for getting all "group" documents that have the userId in there array of users.
I've tried several different ways of query, but I always get an empty array.
What am I doing wrong?
group.js
let mongoose = require('mongoose');
const Group = mongoose.Schema({
name: {
type: String,
required: true
},
users: [{
userId: {
type: mongoose.SchemaTypes.ObjectId,
ref: 'users',
required: true
},
userType: {
type: String,
required: true
},
userStatus: {
type: String,
required: true
}
}]
})
module.exports = mongoose.model('group', Group);
groupController.js
exports.getUserGroups = function (req, res) {
Group.find({
"users.userid": "req.user._id"
}, function (err, groups) {
if (err)
res.send(err)
res.json(groups);
});
}
Field names are case-sensitive, so "users.userid" should be "users.userId" instead:
Group.find({
"users.userId": "req.user._id"
}, ...
You can try using $in operator
db.collection.find({
"users.userId": {
$in: [
req.user._id
]
}
})

Why does MongoDB return empty arrays;

First of all my code is obviously simplified. I create a new field named "followers", in order to store followers names, as array type.
USER SCHEMA
var userSchema = new mongoose.Schema({
local:{
localId:{type:Number},
username:{type:String},
email:{type:String},
followers:{type:Array}
},
facebook:{
facebookId: {type:Number},
username:{type:String},
email:{type:String},
followers:{type:Array}
},
twitter:{
twitterId: {type:Number},
username:{type:String},
email:{type:String},
followers:{type:Array}
}
});
DB record
{ "_id" : ObjectId("...."), "facebook" : { "facebookId" : 10215321125408144, "username" : "johnny", "email" : "johnny#hotmail.com}, "__v" : 0 }
But something weird comes up. When i make a query:
User.findOne({$or: [
{'local.username': 'johnny' },
{ 'facebook.username': 'johnny' },
{ 'twitter.username': 'johnny' },
]}, function(err, user) {
if(err){console.log(err);}
if(!user){
console.log('cannot find user');
}
if(user){
console.log('usrInfo is : '+user);
return res.send(JSON.stringify(user));
}
});
i get as a result:
usrInfo is : { _id: 5a60de744b85e14051e03e2e,
__v: 0,
twitter: { followers: [] },
facebook:
{ facebookId: .....,
username: 'johnny',
email: 'johnny#hotmail.com',
.............,
followers: [] },
local: { followers: [] } }
I cannot understand why
twitter: { followers: [] } and local: { followers: [] }
are showing up. Is there any way to avoid this; Because i'm new in MongoDB i would appreciate any explanation why MongoDB does that. Thanks
This issue occurs because, according to the Mongoose documentation, fields in your schema with type Array implicitly have a default value of []. Try setting the default value to undefined and see if that resolves your problem:
var userSchema = new mongoose.Schema({
local:{
localId:{type:Number},
username:{type:String},
email:{type:String},
followers:{type:Array, default: undefined}
},
facebook:{
facebookId: {type:Number},
username:{type:String},
email:{type:String},
followers:{type:Array, default: undefined}
},
twitter:{
twitterId: {type:Number},
username:{type:String},
email:{type:String},
followers:{type:Array, default: undefined}
}
});

populate following users mongoose

Lemme take time to explain what is happening from start to finish.
Preamble:
A user a follows 10 other people. When user A logs in, an X number of posts from each of the 10 people are pulled into view.
I do not know if it is the right thing to do, and will appreciate a better way of doing it. However, I wanna give it a try, and it ain't working.
Follow Model:
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
let FollowSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
followers: [{
type: Schema.Types.ObjectId,
ref: 'Card'
}],
following: [{
type: Schema.Types.ObjectId,
ref: 'Card'
}]
});
module.exports = mongoose.model('Follow', FollowSchema);
Card Model
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
let CardSchema = new Schema({
title: String,
content: String,
createdById: {
type: Schema.Types.ObjectId,
ref: 'User'
},
createdBy: {
type: String
}
});
module.exports = mongoose.model('Card', CardSchema);
Follow logic
When user A follows user B, do two things:
Push the user_id of B to user A document on field 'following' (A is following B)
Push user_id of A to user B document on field 'followers' (B is followed by A)
router.post('/follow', utils.loginRequired, function(req, res) {
const user_id = req.user._id;
const follow = req.body.follow_id;
let bulk = Follow.collection.initializeUnorderedBulkOp();
bulk.find({ 'user': Types.ObjectId(user_id) }).upsert().updateOne({
$addToSet: {
following: Types.ObjectId(follow)
}
});
bulk.find({ 'user': Types.ObjectId(follow) }).upsert().updateOne({
$addToSet: {
followers: Types.ObjectId(user_id)
}
})
bulk.execute(function(err, doc) {
if (err) {
return res.json({
'state': false,
'msg': err
})
}
res.json({
'state': true,
'msg': 'Followed'
})
})
})
Actual DB values
> db.follows.find().pretty()
{
"_id" : ObjectId("59e3e27dace1f14e0a70862d"),
"user" : ObjectId("59e2194177cae833894c9956"),
"following" : [
ObjectId("59e3e618ace1f14e0a708713")
]
}
{
"_id" : ObjectId("59e3e27dace1f14e0a70862e"),
"user" : ObjectId("59e13b2dca5652efc4ca2cf5"),
"followers" : [
ObjectId("59e2194177cae833894c9956"),
ObjectId("59e13b2d27cfed535928c0e7"),
ObjectId("59e3e617149f0a3f1281e849")
]
}
{
"_id" : ObjectId("59e3e71face1f14e0a708770"),
"user" : ObjectId("59e13b2d27cfed535928c0e7"),
"following" : [
ObjectId("59e3e618ace1f14e0a708713"),
ObjectId("59e13b2dca5652efc4ca2cf5"),
ObjectId("59e21942ca5652efc4ca30ab")
]
}
{
"_id" : ObjectId("59e3e71face1f14e0a708771"),
"user" : ObjectId("59e3e618ace1f14e0a708713"),
"followers" : [
ObjectId("59e13b2d27cfed535928c0e7"),
ObjectId("59e2194177cae833894c9956")
]
}
{
"_id" : ObjectId("59e3e72bace1f14e0a708779"),
"user" : ObjectId("59e21942ca5652efc4ca30ab"),
"followers" : [
ObjectId("59e13b2d27cfed535928c0e7"),
ObjectId("59e2194177cae833894c9956"),
ObjectId("59e3e617149f0a3f1281e849")
]
}
{
"_id" : ObjectId("59f0eef155ee5a5897e1a66d"),
"user" : ObjectId("59e3e617149f0a3f1281e849"),
"following" : [
ObjectId("59e21942ca5652efc4ca30ab"),
ObjectId("59e13b2dca5652efc4ca2cf5")
]
}
>
With the above database results, this is my query:
Query
router.get('/follow/list', utils.loginRequired, function(req, res) {
const user_id = req.user._id;
Follow.findOne({ 'user': Types.ObjectId(user_id) })
.populate('following')
.exec(function(err, doc) {
if (err) {
return res.json({
'state': false,
'msg': err
})
};
console.log(doc.username);
res.json({
'state': true,
'msg': 'Follow list',
'doc': doc
})
})
});
With the above query, from my little understanding of Mongoose populate, I expect to get cards from each of the Users in the following array.
My understanding and expectations might be wrong, however with such an endgoal, is this populate approach okay? Or am I trying to solve an aggregation task with population?
UPDATE:
Thanks for the answer. Getting quite close, but still, the followingCards array contains no result. Here's the contents of my current Follow model:
> db.follows.find().pretty()
{
"_id" : ObjectId("59f24c0555ee5a5897e1b23d"),
"user" : ObjectId("59f24bda1d048d1edad4bda8"),
"following" : [
ObjectId("59f24b3a55ee5a5897e1b1ec"),
ObjectId("59f24bda55ee5a5897e1b22c")
]
}
{
"_id" : ObjectId("59f24c0555ee5a5897e1b23e"),
"user" : ObjectId("59f24b3a55ee5a5897e1b1ec"),
"followers" : [
ObjectId("59f24bda1d048d1edad4bda8")
]
}
{
"_id" : ObjectId("59f24c8855ee5a5897e1b292"),
"user" : ObjectId("59f24bda55ee5a5897e1b22c"),
"followers" : [
ObjectId("59f24bda1d048d1edad4bda8")
]
}
>
Here are all the current content I have from Card Model:
> db.cards.find().pretty()
{
"_id" : ObjectId("59f24bc01d048d1edad4bda6"),
"title" : "A day or two with Hubtel's HTTP API",
"content" : "a day or two",
"external" : "",
"slug" : "a-day-or-two-with-hubtels-http-api-df77056d",
"createdBy" : "seanmavley",
"createdById" : ObjectId("59f24b391d048d1edad4bda5"),
"createdAt" : ISODate("2017-10-26T20:55:28.293Z"),
"__v" : 0
}
{
"_id" : ObjectId("59f24c5f1d048d1edad4bda9"),
"title" : "US couple stole goods worth $1.2m from Amazon",
"content" : "for what",
"external" : "https://bbc.com",
"slug" : "us-couple-stole-goods-worth-dollar12m-from-amazon-49b0a524",
"createdBy" : "nkansahrexford",
"createdById" : ObjectId("59f24bda1d048d1edad4bda8"),
"createdAt" : ISODate("2017-10-26T20:58:07.793Z"),
"__v" : 0
}
With the Populate Virtual example from yours (#Veeram), here's the response I get:
{"state":true,"msg":"Follow list","doc":{"_id":"59f24c0555ee5a5897e1b23d","user":"59f24bda1d048d1edad4bda8","following":["59f24b3a55ee5a5897e1b1ec","59f24bda55ee5a5897e1b22c"],"followers":[],"id":"59f24c0555ee5a5897e1b23d","followingCards":[]}}
The followingCards array is empty.
Using the $lookup query on the other hand simply returns []
I'm likely missing something?
You can use either virtual populate or $lookup operator in aggregation pipeline.
Using Virtual Populate
FollowSchema.virtual('followingCards', {
ref: 'Card',
localField: 'following',
foreignField: 'createdById'
});
Follow.findOne({
'user': Types.ObjectId(user_id) })
.populate('followingCards')
.exec(function(err, doc) {
console.log(JSON.stringify(doc));
});
Using $lookup aggregation
Follow.aggregate([
{
"$match": {
"user": Types.ObjectId(user_id)
}
},
{
"$lookup": {
"from": "cards",
"localField": "following",
"foreignField": "createdById",
"as": "followingCards"
}
}
]).exec(function (err, doc) {
console.log(JSON.stringify(doc));
})
var mongoose = require('mongoose'), Schema = mongoose.Schema
var eventSchema = Schema({
title : String,
location : String,
startDate : Date,
endDate : Date
});
var personSchema = Schema({
firstname: String,
lastname: String,
email: String,
dob: Date,
city: String,
eventsAttended: [{ type: Schema.Types.ObjectId, ref: 'Event' }]
});
var Event = mongoose.model('Event', eventSchema);
var Person = mongoose.model('Person', personSchema);
To show how populate is used, first create a person object,
aaron = new Person({firstname: 'Aaron'}) and an event object,
event1 = new Event({title: 'Hackathon', location: 'foo'}):
aaron.eventsAttended.push(event1);
aaron.save(callback);
Then, when you make your query, you can populate references like this:
Person
.findOne({ firstname: 'Aaron' })
.populate('eventsAttended') .exec(function(err, person) {
if (err) return handleError(err);
console.log(person);
});
// only works if we pushed refs to person.eventsAttended
note: change Activity.find to Card.find
const { ObjectID } = require("mongodb");
// import Follow and Activity(Card) schema
const userId = req.tokenData.userId; // edit this too...
Follow.aggregate([
{
$match: {
user: ObjectID(userId)
}
}
])
.then(data => {
// console.log(data)
var dataUsers = data[0].following.map(function(item) {
return item._id;
});
// console.log(dataUsers)
Activity.find(
{ createdById: { $in: dataUsers } },
{
_id: 1,
title: 1,
content: 1,
createdBy: 1,
creatorAvatar: 1,
activityType: 1,
createdAt: 1
}
)
// .sort({createdAt:-1)
.then(posts => res.send({ posts }));
});