Let's say I want to look up a user by their _id and check if the "liked" value (array) contains a certain post _id. How do I query the db for this action? Is it okay to just store these _id's in an array or does mongodb convention prefer something else to store as a reference to other documents?
So I just want to check if the user has the post _id in the "liked" array.
var users = new mongoose.Schema({
name : {type: String, unique : true, required : true, dropDups: true},
password : {type: String, required : true}, //hash
liked : [String],
created : {type: Date, default: Date.now}
});
Here is how I think this might look:
function checkIfLiked() {
let uname = "Jim";
let postId = "abc";
//check if $USER has `postId` in $LIKED
user.findOne({$USER: uname},{$LIKED: {$in: postId} }, function(err, results) {
//do something after check
});
}
For the user data
{ "_id" : ObjectId("56effca6e668e15e2eaa6dfe"), "liked" : [ "11", "23", "4" ], "name" : "aa" }
{ "_id" : ObjectId("56effcb1e668e15e2eaa6dff"), "liked" : [ "1", "2", "3" ], "name" : "bb" }
To check the user name aa with 4 in liked array
> db.user.find({liked: '4', name: 'aa'})
{ "_id" : ObjectId("56effca6e668e15e2eaa6dfe"), "liked" : [ "11", "23", "4" ], "name" : "aa" }
but
> db.user.find({liked: '2', name: 'aa'})
No matched result.
Is it okay to just store these _id's in an array or does mongodb convention prefer something else to store as a reference to other documents?
Mongoose population could do that, you can define the user schema as below
var users = new mongoose.Schema({
name : {type: String, unique : true, required : true, dropDups: true},
password : {type: String, required : true}, //hash
liked : [{ type: Schema.Types.ObjectId, ref: 'User' }],
created : {type: Date, default: Date.now}
});
var User = mongoose.model('User', users);
Related
I am using mongoose and I am trying to get users from my mongodb database, Here is what part of my json looks like
"hpCDaKverVWEYukAhAcM8NU6SP73" : {
"admin" : false,
"booksBorrowed" : [ {
"id" : "9780321831552",
"timeStamp" : 1618881802437
}, {
"id" : "9780007204496",
"timeStamp" : 1618881803678
}, {
"id" : "9780316491297",
"timeStamp" : 1618882675513
}, {
"id" : "9780440335160",
"timeStamp" : 1618882676756
}, {
"id" : "9781482287325",
"timeStamp" : 1618887153684
} ],
I am trying to get the books borrowed array
i tried creating a new schema like this
const BorrowedBook = new Schema({
id : {type: String, default: ''},
timeStamp : {type: Number, default: 0},
})
then doing this in mongoose.model
booksBorrowed: [BorrowedBook]
then I do this in server.js
const User = require('./models/user')
app.get('/api/users', function (req, res) {
User.find(function (err, users) {
console.log(users)
})
})
but it just prints this
booksBorrowed: [ [Object], [Object], [Object], [Object], [Object] ],
What am I doing wrong?
You are doing nothing wrong, its just console.log(users) printing this, since it doesnt print nested lvl objects.
You can do console.log(JSON.stringify(users)) or console.dir(users).
When I run this code in node.js my embedded document id doesn't match with the related id in the other collection.
const fruitSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
rating: {
type: Number,
min: 1,
max: 10,
},
review: String
});
const Fruit = mongoose.model("Fruit", fruitSchema);
const watermelon = new Fruit({
name: "Watermelon",
rating: 7,
review: "Meh."
});
// watermelon.save();
const personSchema = new mongoose.Schema({
name: String,
age: Number,
favouriteFruit: fruitSchema
});
const Person = mongoose.model("Person", personSchema);
const person = new Person({
name: "John",
age: 37,
favouriteFruit: watermelon
});
person.save();
As a result, in MongoDB I get, From
db.fruits.find()
{
"_id" : ObjectId("5e7444c37ce78dd238d0f994"),
"name" : "Watermelon",
"rating" : 7,
"review" : "Meh.",
"__v" : 0
}
From
db.people.find()
{
"_id" : ObjectId("5e7451d971df90096974be01"),
"name" : "John",
"age" : 37,
"favouriteFruit" :
{
"_id" : ObjectId("5e7451d971df90096974be00"),
"name" :"Watermelon",
"rating" : 7,
"review" : "Meh."
},
"__v" : 0
}
I think I'm missing something with the Model.updateOne method.
I'm just trying to add an embedded document into another document.
I'm just a beginner, so any links or help would be amazing!
Thanks!
Why such behavior?
The reason you are having different _ids in the two fruits object that are supposed to be the same is that you did not add the _id property to the fruit schema and because _id is a required property of all MongoDB document, mongoose would help you auto-generate a new _id when it creates the query to send to the database. The _id it generates when you run watermelon.save() is different from the _id it generates when you run person.save(), this is why you are seeing the two different _ids.
The fix:
What you need to do is add the _id property to the fruit schema(and maybe the person schema to avoid further surprises) and then explicitly generate an _id your self before saving the document into the database.
The fruit schema should be like this after adding the _id property:
const fruitSchema = new mongoose.Schema({
_id: mongoose.ObjectId,
name: {
type: String,
required: true
},
rating: {
type: Number,
min: 1,
max: 10,
},
review: String
});
And when instantiating the fruit model, add the _id value yourself:
const watermelon = new Fruit({
_id: mongoose.Types.ObjectId(), // this helps generate a unique objectId
name: "Watermelon",
rating: 7,
review: "Meh."
});
I've defined my schema as follow but when I did db.Titles.find() from mongo shell I didn't get all the documents I have listed. What's wrong did I do ? The author is not showing in the mongo shell. I've tried to add some random document in the list still not showing in the mongo ? Once a model is created, can't it be updated or change? This created a problem when I try to access the list in template. Thanks, in advance.
model :
var mongoose = require("mongoose");
var tSchema = new mongoose.Schema({
title: String,
sypnosis: String,
category: Array,
author: {
username: String,
id: { type: mongoose.Schema.Types.ObjectId, ref: "User" }
},
parts: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Part"
}
],
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
]
});
var Title = mongoose.model("Title", tSchema);
module.exports = Title;
Mongo shell query :
db.titles.find().pretty()
{
"_id" : ObjectId("5e0d140e7bf04c6a60f97dbd"),
"category" : [ ],
"parts" : [ ],
"comments" : [ ],
"title" : "New Title",
"sypnosis" : "This si a sypnosis",
"__v" : 0
}
I would like to add a photo into a country in mongoose. But country is an array and photo too. Here is my user schema :
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
firstName: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
birthDate: {
type: Date,
required: true
},
sex: {
type: String,
required: true
},
countries: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Country',
photos: [
{
base64: {
type: String,
required: true
},
title: String,
description: String
}
]
}
],
admin: {
type: Number,
required: true
}
});
Here is what I got as data into mongoDB :
The problem is that I only got the id of countries. And I would like to use another field of the document country. Populate works well when I want to get data, but how to populate and then use the fields to update with mongoDB?
Moreover, I don't know how to update data into nested array, I tried :
User.findOneAndUpdate(
{
"name": "CHARLAT",
"countries": "5d2d847b06f2f94118a36518"
},
{ $push : { "countries.photos" : {
base64: "bla"
} }}
)
As you can see, I use a hand written id for country... I could do a find query before on country but can we use populate here?
And I got this in Postman :
Thank you in advance for your help !
If the type is ObjectId, it can't have a photos field, since it's just an _id. It is a reference to another collection.
Updated answer after comments :
The best thing to do IMO is to create a Photo model which would have the file path and the country's _id. The User model would only store a list of Photos [_id].
UserSchema :
{
.....
photos : [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Photo'
}],
.....
}
PhotoSchema :
{
country : {
type: mongoose.Schema.Types.ObjectId,
ref: 'Country'
},
path : String
}
Then, query your Users this way, by populating the photos, and inside each photo, populating the countries :
UserModel
.find(conditions)
.populate({
path: 'photos',
model: 'Photo'
populate: {
path: 'country',
model: 'Country'
}
})
.lean() // Faster and lighter for read-only, simply returns an object
So you should get a User object like this :
{
.....
name : "John",
photos : [{
country : {
name : "Country 1",
code : "C1" // or whatever field you have in your Country model
},
path: "path/to/photo1.jpg"
},
{
country : {
name : "Country 2",
code : "C2"
},
path: "path/to/photo2.jpg"
}]
.....
}
I'm just wondering how I can update a nested array field inside a mongo db document.
Here is how my schema looks like:
const userSchema = new Schema({
email: {type: String, unique: true, lowercase: true},
password: String,
firstName: String,
lastName : String,
role: String,
children: Array
});
This is how the document looks like:
{
"_id" : ObjectId("5b3570f3150a0b57a4e7421e"),
"children" : [
{
"fullName" : "John doe",
"yearGroup" : "4",
"absences" : [],
"id" : "765"
}
],
"email" : "jdoe#gmail.com",
"firstName" : "John",
"lastName" : "Doe",
"role" : "parent",
"__v" : 1
}
Where I want to push a new object into to 'absences' array.
to do this you have to use the mongodb $push operator via the update operation, which i guess that is what you want to do, but you did not specify your match query. To push to absences do this ( i assume the match query is children.fullName )
db.ops.update( { "children.fullName": "John doe" } , { $push: { "children.$.absences": "data to push" } } );
the $ placeholder tells mongodb to replace it self ( i.e $ ) with the matched array index.
incase you want to prevent duplicate elements in absences field you have to use the $addToSet operator
db.ops.update( { "children.fullName": "John doe" } , { $addToSet: { "children.$.absences": "data to push" } } );