How to use model.findbyid and query inside it? - node.js

This is a simple question for you guys...I am wondering how can I acess a specific Id that is inside the "followers", after querying the User by its id. In other words i am searching for the user by its Id, and then I want to check the ids that are inside the followers.
For example: I have an Id saved in one variable "x", and I want to check if this Id "x" is inside of the followers array.
The model looks like this:
var UserSchema = new mongoose.Schema({
followers: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
]
});
module.exports = mongoose.model("User", UserSchema);
And the code that I am using is this one:
User.findById(req.params.id,'followers', function(err,name){
if(err){
console.log(err)
} else{
console.log(name);
}
});
It looks like I can print the user id and the id's that are inside the "followers", but i am not managing to see if the desired Id is inside of "followers" array or not.Can anyone help me with it?
Thank you for your attention!

I think you need to create nested for loop because you have an array of users according to user schema and each user has an array of followers and to solve this, you need to create for loop for user schema and inside that loop you will loop through all followers inside that user and check whether the id that you have equals to their id.

Since followers is an array of IDs (document references), if the query is for a single follower match you can use a shorthand of {followers: SOME_ID} or if it is an array then you can use {followers: {$all: [SOME_ID, SOME_OTHER_ID]}}. See the Mongo documentation for more information.
Using an array to match for example would look like the following.
User.findOne({_id: req.params.id, followers: {$all: [SOME_ID, SOME_OTHER_ID]}}, function(err, name) {
if (err) {
console.log(err)
} else {
console.log(name);
}
});

Related

query array content in Mongodb

var ConversationSchema = new Schema({
conversationName:String,
conversationID: String,
participants: [
{
Id:String
}
]
})
I'm trying to query the conversation schema to return every conversation where the participant array contain the id of the user i'm looking at. In node js please
The simplest way to query a array of subdocuments in mongo (using example given in question)
// just query here
{ 'participants.Id': <value> }
Here is more documentation https://docs.mongodb.com/manual/tutorial/query-array-of-documents/

Mongo / Express Query Nested _id from query string

Using: node/express/mongodb/mongoose
With the setup listed above, I have created my schema and model and can query as needed. What I'm wondering how to do though is, pass the express request.query object to Model.find() in mongoose to match and query the _id of a nested document. In this instance, the query may look something like:
http://domain.com/api/object._id=57902aeec07ffa2290f179fe
Where object is a nested object that exists elsewhere in the database. I can easily query other fields. _id is the only one giving an issue. It returns an empty array of matches.
Can this be done?
This is an example and not the ACTUAL schema but this gets the point across..
let Category = mongoose.Schema({
name: String
})
let Product = mongoose.Schema({
name: String,
description:String,
category:Category
})
// sample category..
{
_id:ObjectId("1234567890"),
name: 'Sample Category'
}
// sample product
{
_id:ObjectId("0987654321"),
name:'Sample Product',
description:'Sample Product Description',
category: {
_id:ObjectId("1234567890"),
name: 'Sample Category'
}
}
So, what I'm looking for is... if I have the following in express..
app.get('/products',function(req,res,next){
let query = req.query
ProductModel.find(query).exec(function(err,docs){
res.json(docs)
})
})
This would allow me to specify anything I want in the query parameters as a query. So I could..
http://domain.com/api/products?name=String
http://domain.com/api/products?description=String
http://domain.com/api/products?category.name=String
I can query by category.name like this, but I can't do:
http://domain.com/api/products?category._id=1234567890
This returns an empty array
Change your query to http://domain.com/api/object/57902aeec07ffa2290f179fe and try
app.get('/api/object/:_id', function(req, res) {
// req._id is Mongo Document Id
// change MyModel to your model name
MyModel.findOne( {'_id' : req._id }, function(err, doc){
// do smth with this document
console.log(doc);
});
});
or try this one
http://domain.com/api/object?id=57902aeec07ffa2290f179fe
app.get('/api/object', function(req, res) {
var id = req.param('id');
MyModel.findOne( {'_id' : id }, function(err, doc){
console.log(doc);
});
})
First of all increase your skills in getting URL and POST Parameters by this article.
Read official Express 4.x API Documentation
Never mind I feel ridiculous. It works just as I posted above.. after I fixed an error in my schema.

How to use ref to store a document correctly in mongodb - mongoose?

I am trying to store a ref of a user model in my users - followers Array:
The model looks something like this:
User = require('../models/user.js');
ObjectId = mongoose.Schema.Types.ObjectId;
User = new Schema({
followers: [{ type: ObjectId, ref: 'User' }],
Now I am trying to store every time a user follows a user like so:
User.findByIdAndUpdate({_id: myId}, { $addToSet: {followers: user._id,
However, this only stores the string and not the whole user object? Is that how it is suppose to be? If so, then to grab it out the rest of the info do I just need to do a populate query?
If it is suppose to store the whole object then does it update as well as the object gets updated?
I was going to remove the question as I figured it out, but I see that people up-voted it so to help them out, I shall post my discoveries.
Apparently it will just store the id, and to then call it I used a basic populate call on it like so:
User
.findOne({ _id: myId })
.populate('followers', '_id name count') //
.exec(function (err, doc) {
if (err) return handleError(err);
})

Mongoose nested reference population

I'm having trouble understanding some of the concepts behind mongoose's populate methods. I had an embedded approach working first, although, as I feared a big overhead of data and out-of-sync documents going around I tried changing the paradigm to ref other documents.
My Schema is similar to the following (removed irrelevant properties):
var userSchema = mongoose.Schema({
name: {type: String, default:''},
favorites:{
users:[{type: Schema.Types.ObjectId, ref: this}],
places:[{type: Schema.Types.ObjectId, ref: PlaceSchema}]
}
});
module.exports = mongoose.model('User', userSchema);
Now I'm trying to get a User's favorites like this:
User.findOne({_id: currentUser}).exec(function(err, user){
console.log(user);
if (err)
throw err;
if(!user){
console.log("can't find user");
}else{ // user found
user.populate('favorites.users');
user.populate('favorites.places');
// do something to the 'user.favorites' object
}
});
Although this doesn't work as intended, as both user.favorites.users and user.favorites.places come up undefined.
I thought that I could populate as above, but apparently, that's not the case. From what I read, I must be missing something indicating (maybe) the model of the ref'ed document? This flow is very new to me and I'm kinda lost.
Is there anyway I can get an array of users and places by populating my query result as above? I tried populate chained with exec and it doesn't work either. Is there a better way to achieve this result?
EDIT: In case it's needed, in the DB, a User document shows up as:
{
"_id": "56c36b330fbc51ba19cc83ff",
"name": "John Doe",
"favorites": {
"places": [],
"users": [
"56b9d9a45f1ada8e0c0dee27"
]
}
}
EDIT: A couple more details... I'm currently storing/removing the reference ObjectIds like this (note targetID is a String):
user.favorites.users.push({ _id: mongoose.Types.ObjectId(targetID)});
user.favorites.users.pull({ _id: mongoose.Types.ObjectId(targetID)});
Also, I need to populate the users and places with their respective documents aswell, I think that might not be clear in my original question.
Well, I figured out what I needed by paying proper attention to the docs (and also with #DJeanCar 's (+1'd) help/pointers).
By Mongoose's docs regarding Populating across multiple levels, I've reached this solution:
User.findOne({_id: currentUser})
.populate({path:"favorites.users", populate: "name"})
.populate({path:"favorites.places", populate: "name"})
.exec(function(err, user){
if(err)
throw err;
if(!user){
console.log("couldnt find source user");
}else{
// here, user.favorites is populated and I can do what I need with the data
}
});
Also, from what I could tell, you can also pass select: "field field field" in populate()'s options, should you need to filter the document fields you require after population.
Hope this helps someone with similar issues!
Try:
User
.findOne({_id: currentUser})
.populate('favorites.users')
.populate('favorites.places')
.exec( function (err, user) {
// user.favorites.users
// user.favorites.places
});

MongoDB: handling auto-incrementing model id's instead of Mongo's native ObjectID

Due to a management decision, we are using userId for the users collection, postId for the posts collection, and topicId for the topics collection, instead of '_id' for each collection as the unique identifier.
This causes a few problems getting started - one of the problems I have encountered is with upserts -
Using Mongoose, we have a schema that restricts userId to be a unique value - but when doing an update on a user model, with upsert set to true, MongoDB appears to only look at the ObjectIds of a collection to see if the same one exists - it doesn't check to see if a model already exists with the same userId - therefore Mongo does an insert instead of an update.
let me illustrate this with some data:
let's say the user's collection has one document:
{
_id:'561b0fad638e99481ab6d84a'
userId:3,
name:'foo'
}
we then run:
User.update({userId:3},{"$set":{name:'bar'},{upsert:true},function(err,resp){
if(err){
// "errMessage": "insertDocument :: caused by :: 11000 E11000 duplicate key error index: app42153482.users.$userId_1 dup key: { : 3 }",
}
});
one would think that MongoDB would find the existing document with userId:3 and udpate it, so there must be something I am doing wrong since it's giving me the duplicate key error?
Typically the default value ObjectId is more ideal for the _id. Here, in this situation you can either override the default _id or you can have your own field for id(like userId in your case).
Use a separate counters collection to track the last number sequence used. The _id field contains the sequence name and the seq field contains the last value of the sequence.
Insert into the counters collection, the initial value for the userid:
db.counters.insert( {
_id: "userid",
seq: 0 } )
Create a getNextSequence function that accepts a name of the sequence. The function uses the findAndModify() method to atomically increment the seq value and return this new value:
function getNextSequence(name) {
var ret = db.counters.findAndModify(
{
query: { _id: name },
update: { $inc: { seq: 1 } },
new: true
}
);
return ret.seq;
}
Use this getNextSequence() function during insert().
db.users.insert(
{
_id: getNextSequence("userid"),
name: "Sarah C."
}
)
db.users.insert(
{
_id: getNextSequence("userid"),
name: "Bob D."
}
)
This way you can maintain as many sequences as you want in the same counter collection. For the upsert issue, check out the Optimistic Loop block in this link Create an auto-increment sequence field.
The second approach is to use a mongoose middleware like mongodb-autoincrement.
Hope it helps.
I don't know which versions of MongoDB and Mongoose you are using, but I couldn't reproduce your problem with MongoDB 3.0 and Mongoose 4.1.10.
I made a sample for you which will create and save a new user, update (using upsert) it, and create another one through an upsert. Try running this code:
"use strict";
var mongoose=require("mongoose");
var Schema = require('mongoose').Schema;
var ObjectId = mongoose.Schema.Types.ObjectId;
// Connect to test
mongoose.connect("mongodb://localhost:27017/test");
// Lets create your schema
var userSchema = new Schema({
_id: ObjectId,
userId: {type: Number, unique: true },
name: String
});
var User = mongoose.model("User", userSchema, "Users");
User.remove() // Let's prune our collection to start clean
.then( function() {
// Create our sample record
var myUser = new User({
_id:'561b0fad638e99481ab6d84a',
userId:3,
name:'foo'
});
return myUser.save();
})
.then( function() {
// Now its time to update (upsert userId 3)
return User.update({userId:3},{"$set":{name:'bar'}},{upsert:true});
})
.then( function() {
// Now its time to insert (upsert userId 4)
return User.update({userId:4},{"$set":{name:'bee'}},{upsert:true});
})
.then( function() {
// Lets show what we have inserted
return User.find().then(function(data) {console.log(data)});
})
.catch( function(err) {
// Show errors if anything goes wrong
console.error("ERROR", err);
})
.then( function() {
mongoose.disconnect();
});
Following the documentation (of MongoDB 3.0) upsert:true will only not insert a non-existing document if your query conditions match on the _id field.
See: https://docs.mongodb.org/manual/reference/method/db.collection.update/#mongodb30-upsert-id
Why are you not using the user_name for a user as unique id?
Because auto-incrementing fields as ids are a bad practice to use in a mongodb environment, especially if you want to use sharding
=> all your inserts will occur on the latest shard
=> the mongodb cluster will have to rebalance often / redistribute the data around.
(Currently this will not occur on your system as you still use the generated _id field)
You can off course also create a unique index on the user_id field:
https://docs.mongodb.org/manual/core/index-unique/#index-type-unique

Resources