SailsJs: how to use find for array of object attribute? - mongodb

i have a model that it has some json type attribute and now I want to use find on this json attribute. may please help how can i do it?
model:
module.exports = {
attributes: {
ownerInfo: {
type: 'json',
description: 'owner info of Task',
example: {id: '', fullName: '', emailAddress: ''}
},
name: {
type: 'string',
required: true,
description: 'Name of Task',
example: 'Business App'
},
users: {
type: 'json',
columnType: 'array',
description: 'Users id of task',
defaultsTo: [],
example: [{id :'', emailAddress: '', fullName: '', status: ['admin', 'leader', 'user']}]
}
}
}
actually i need 2 different query, one for finding ownerInfo.id and another else is finding user[].id.
in second query attribute is Array.
I searched a lot in Internet and tried many time with the queries like below but have not got any result.
tasks = await Task.find({
where: {
ownerInfo: {
id: params.id
}
}
})
for Array i had no any Idea how to search in Array of Object. please share your Idea.
tasks = await Task.find({
where: {
users: {
// how to search status of user ??
}
}
})
and also in MongoDb better I save short user info in task collection or like relative DB only keep the id of them and with populate reach that data? which method is faster and better as performance?
advanced thanks

Related

Ensure a unique index on nested reference on a mongoose schema

What I want is that a user can like a post only once, hence I uniquely indexed the user in the likes array to ensure the same, but it isn't working and I can't find out what is wrong here .
The schema looks like this :
const mongoose = require('mongoose')
const postSchema = new mongoose.Schema({
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User' // User model
},
text: {
type: String,
required: [true, 'Post must have some text']
},
likes: [
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
}
],
comments: [
{
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
text: {
type: String,
required: [true, 'Comment must have some text']
},
addedAt: {
type: Date,
default: Date.now
}
}
],
createdAt: {
type: Date,
default: Date.now
}
})
postSchema.pre(/^find/, function(next) {
this.populate({
path: 'author',
select: 'name avatar'
}).populate({
path: 'comments.author',
select: 'name avatar'
})
next()
})
// Ensure a user can like a post only once
postSchema.index({ 'likes.user': 1 }, { unique: true })
const Post = mongoose.model('Post', postSchema)
module.exports = Post
However when I send a post request to like a post twice via the same user it
shows no error.
Here is the postman output
I have tried both the ways listed in this, but none of them worked in this case.
Mongoose Index on a field in nested document
How do I ensure a user can like a post only once from the schema itself ?
Try saving likes in this format in the database
likes:[{type:mongoose.Schema.Types.ObjectId,ref: 'User'}]
making it
likes:[ObjectId("5af03111967c60501d97781f")]
and when the post like API is hit do
{$addToSet: {likedBy: userId}}
in update query,addToSet ensures no duplicate ids are maintained in the array.

Mongoose: reference between models with same schema keys

As a front-end developer, I would like to have some isomorphic object for two mongoose models.
Let's say I have a user profile:
const profileSchema = new Schema({
firstName: { type: String },
lastName: { type: String },
// example of difference between model schemas
__user: { type: ObjectId, ref: 'Users' },
}
And I would like to create a list of Contact, where each contact will have some of the same keys:
const contactSchema = new Schema({
firstName: { type: String },
lastName: { type: String },
__profile: {
type: ObjectId,
ref: 'Profiles',
unique: true,
},
comment: { type: String },
}
NOTE: Contact could be the both:
as a reference to the Profile
and as independent record in DB / document.
==============================
My question: which is the best way to, organize models on such a way, so
contact could be a reference to the profile
when similar Profile key, like firstName will be updated, contact firstName will be updated too
AVOID of next ref
await Contact.findById(SOME_ID).populate('__profile');
// result
{
firstName: '',
lastName: '',
__profile: {
firstName: 'Chuck',
lastName: 'Norris',
}
}
Desired result - keep contact "isomorphic" like:
{
firstName: 'Chuck', // the key value from profile
lastName: 'Norris', // the key value from profile
__profile: SOME_PROFILE_ID,
}
Is this possible?
P.S: in my app, I'm using refs and started to use discriminators approaches.
I'd approach this task either:
1) put all data inside 1 collection (e.g. Profile):
// Profile model
{
firstName: 'Chuck',
lastName: 'Norris',
contacts: [{
type: ObjectId,
ref: 'Profile',
unique: true,
}],
...all other properties
}
that way you will be able to store just contacts (e.g. when I want to add just a contact) and profiles with much more info.
2) or will use discriminators to create a base class (e.g. Contact) and build Profile model upon it:
const options = { discriminatorKey: 'userType' };
const Contact = mongoose.model('Contact', new mongoose.Schema({
firstName: String,
lastName: String
},
options)
)
const Profile = Contact.discriminator(
'Profile',
new mongoose.Schema(
{
contacts: [{
type: ObjectId,
ref: 'Contact',
unique: true,
}],
comments: []
},
options
)
);
that way you will be able to save Contacts and Profiles inside 1 collection and reference base class (Contact) for contacts inside Profile
Hope that helps!
In my case, complete usage of Mongoose discriminators did not give me an advantage, because discriminators give you an opportunity to:
They enable you to have multiple models with overlapping schemas on
top of the same underlying MongoDB collection.
As a result, by using discriminators approach, I will reive one collection
of:
profiles
And there will be a mix of users and contact profiles.
==============================
So I decided to use two approaches:
create BesaSchema for the profile
take advantage of Mongoose Subdocuments
RESULT:
// keys which are same for both user Profile and Contact
const Schema = require('mongoose').Schema;
const util = require('util');
function BaseProfileSchema(...args) {
Schema.apply(this, args);
this.add({
firstName: { type: String },
lastName: { type: String },
});
}
util.inherits(BaseProfileSchema, Schema);
// user Profile Model
const profileSchema = new BaseProfileSchema({
__user: {
type: String,
ref: 'users',
required: true,
unique: true,
},
});
const Profile = mongoose.model('profiles', profileSchema);
// Contact with profile as subdocument
const contactProfileSchema = new BaseProfileSchema();
const contactSchema = new Schema({
// Associations
__refProfile: {
type: Schema.Types.ObjectId,
ref: 'profiles',
index: {
unique: true,
sparse: true,
},
},
profile: contactProfileSchema,
});
const Contact = mongoose.model('contacts', contactSchema);
As a result, I'm having DB with next collections:
users
profiles
contacts
Both profiles and contacts.profile are IDENTICAL because I'm extending the base shared schema.
Moreover:
inside Contact I'm having different keys for real referenced profile (__refProfile which can NOT be edit by others) and contact.profile
profile inside connection can be edited ONLY when the contact was edited by itself
P.S: happy codding 👨‍💻🍻

Waterline: Create or update a populate record

My question is basic but I can not find an answer in the documentation. I have two models: 'Person' and 'Location' being associated One-to-one. I want to create or update 'populated child records' in the Location collection.
let person = await Person.findOne({ phone: inputs.phone }).populate('reside');
Well return
{ reside: [],
createdAt: 1540081110195,
updatedAt: 1540331824622,
id: '5bcbc5d609618e2cfbe64883',
phone: '+42424242',}
I want to create new location record (when they do not exist) or update if their exist. I try
let location = await Location.update({ id: person.reside.id })
.set({city: inputs.city,
street: inputs.street,
}).fetch;
But it does not work when no record has been created yet.
model/Person.js
phone: {
type: 'string',
unique: true,
},
reside: {
collection:'location',
via: 'owner'
},
models/Location.js
city: { type: 'string' },
street: { type: 'string' },
owner:{
model:'person',
unique: true
}
I use action2
I finally found here methods .addToCollection(), .removeFromCollection(), or .replaceCollection() to modify the populated values of a particular record or set of records. It does not seem to be the most appropriate place in the doc to talk about it

MissingSchemaError while using Mongoose Populate with only one model

**I have answered below. In short you need to require the Model in the module in which you wish to populate, even though you do not refer to it directly.
I am hitting a strange problem with mongoose when populating just one particular array of IDs.
I have three models, User, Company and Widgets.
When I return the company populated with the users all is fine using:
Company.findOne({ name: 'xyz' })
.populate('users')
.exec(function(err, company) {
if (err) return res.send(err)
res.send(company)
})
However when I try to replace populate 'users' with 'widgets' I get the following error:
{
"message": "Schema hasn't been registered for model \"widget\".\nUse mongoose.model(name, schema)",
"name": "MissingSchemaError"
}
Here are the models:
USER:
const UserSchema = new Schema({
name: String,
email: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
},
company: {
type: Schema.Types.ObjectId,
ref: 'company'
}
});
const User = mongoose.model("user", UserSchema);
COMPANY:
const CompanySchema = new Schema({
name: String,
URL: {
type: String,
unique: true
},
users: [{
type: Schema.Types.ObjectId,
ref: 'user'
}],
widgets: [{
type: Schema.Types.ObjectId,
ref: 'widget'
}]
});
const Company = mongoose.model('company', CompanySchema);
WIDGET:
const WidgetSchema = new Schema({
title: {
type: String,
required: true
},
maker: String
});
const Widget = mongoose.model('widget', WidgetSchema);
I have manually inspected the _ids in the widget array of the company model and they are all correct.
OK, so this was a lack of understanding on my behalf.
In the module where I was using:
Company.findOne({ name: 'xyz' })
.populate('users')
.exec(function(err, company) {
if (err) return res.send(err)
res.send(company)
})
I had imported the User model for other uses in the module. However, as I was not directly referring to Widget I had not imported it. Having done some more research I found that you need to import a model when populating even though not referring to it directly.
Let me know if best to delete whole thread or leave for reference.

find all kinds but get one for every kind in mongodb

I create MessageScheme to save a message between two users, one document for one message. Now I want to find a list of people who have chated with specific person, what should I do?
I did this way, but it is not efficiency:
Message.find({$or: [{receiverId: specificId}, {senderId: specificId}]
}).sort('-created').limit(100).exec(function (err, results) {
res.jsonp(results) //the results will content all documents have specificId
})
This is the model in mongodb
var MessageSchema = new Schema({
created: {
type: Date,
default: Date.now
},
content: {
type: String,
default: '',
trim: true
},
senderId: {
type: String,
default: '',
},
receiverId:{
type: String,
default: '',
}
});