I post here , because I recently start a development project with sails and MongoDB 3.0.2.
I am a beginner with this framework and his ORM (aka waterline).
In my project I've two classes : listeners and titles, and I need to do this relations :
N Listeners can add to her favorite N titles -> Many to Many.
This is the sample of my classes :
Listeners :
module.exports = {
schema : true,
autoPK : false,
attributes: {
name : {
type: 'string' ,
required : true,
string : true,
notNull:true
},
email : {
type: 'email' ,
required : true,
email :true,
notNull:true,
unique: true,
primaryKey:true
},
password : {
type: 'string',
required : true,
string:true,
minLength : 6,
notNull:true
},
favorites:{
collection :"title",
via : "bookmarkedBy",
dominant: true
}
//....
addFavoriteTitle:function(userID,titleID,callback){
User.findOne(userID).exec(function(error, user) {
if(!error && user){
user.favorites.add(titleID);
user.save(function(error) {});
callback(error,user);
} else{
callback(error,user);
}
});
},
}
Titles :
module.exports = {
schema : true,
autoPK : false,
attributes: {
title : {
type: 'string',
required : true,
//string : true,
notNull:true,
unique : true,
primaryKey:true
},
artist : {
type: 'string',
required : true,
string : true,
notNull:true
},
artwork : {
type: 'string'
},
playing:{
type:'boolean',
defaultsTo:false
},
bookmarkedBy:{
collection : "user",
via : "favorites"
},
},
//.....
}
I followed the official documention of sails, but I don't see / undestand :
How to recover the information on a title from the information contained in the relationship: " favorites" of the user class .
And how do from the relationship " bookmarkedBy " Class Title , to find / access information on a user who has the title in his "favorites".
So, I fail to use the relationship between the two classes , even according to the documentation.
Can you help me ?
Related
I have a collection of posts.
Each post can have many likes, comments and can be shared by many users.
Each comment can also be liked by many users.
It's looking like this:
let post = await PostModel.findAll({
where: { _id: req.params.id },
include : this.include
});
And the include is:
this.include =
[
{
model: UserModel,
as: "likes",
attributes: [
"_id",
],
},
{
model: CommentPostModel,
as: "comments",
attributes : ["_id"],
include: [{
model: UserModel,
as: "likes",
attributes: [
"username",
],
}]
}]
What I want is to be able to find the posts trending at X time.
(Time impact as the score.)
To be able to achieve this goal, I tried ordering like this:
let top = 1 + (post.likes.length + (3 * post.shareBy.length));
if (post.comments) {
top += 2 * post.comments.length ;
let allReply = 0;
for (let com of post.comments) {
allReply += com.likes.length;
}
top += allReply;
}
const deltaTime = (new Date() - new Date(post.createdAt)) / 3600 / 1000;
post.trendIndicator = Math.floor((top * top) / (deltaTime / 168));
And to order by post.trendIndicator.
Currently what I do is:
I have a col trendIndicator in the PostModel. Each time a user interacts with the post, I calculate and update the score.
But if one post has 100000 in score and nobody interacts with the post, the score will be 10000 forever.
If someone knows if it's possible to do this, it will be very appreciable.
I think about one solution, if someone can help
This is my model :
const PostModel = sequelize.define( 'Post',
{
_id : { primaryKey: true, type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4 },
type : {
allowNull : false,
defaultValue : 'post',
type : DataTypes.STRING(24)
},
text: {
type : DataTypes.TEXT(),
allowNull : true,
validate: {
len: {
args: [0,1800],
msg: "String length is not in this range [1-1800]"
}
}
},
privacy: {
type : DataTypes.STRING(12),
defaultValue : "public",
allowNull : false
},
editTime: {
type : DataTypes.DATE(),
allowNull : true
},
shareBy: {
type : DataTypes.ARRAY(DataTypes.STRING(58)),
defaultValue: [],
},
trendIndicator: {
type : DataTypes.INTEGER,
defaultValue: 999,
allowNull : false
},
gifLink: {
type: DataTypes.STRING(150),
allowNull : true
},
pinned: {
type: DataTypes.BOOLEAN,
defaultValue: false,
},
survey : {
type: DataTypes.JSON,
allowNull : true
},
latitude : {
type: DataTypes.FLOAT,
allowNull : true
},
longitude : {
type: DataTypes.FLOAT,
allowNull : true
},
views : {
type : DataTypes.INTEGER,
defaultValue : 0
},
tags : {
type : DataTypes.ARRAY(DataTypes.STRING(50)),
defaultValue: [],
}
},
{ timestamps: true }
)
What I Want to do
let arrayOfPost = [id1,id2....]
await PostModel.update(
{ trendIndicator : Sequelize.literal('Length of comments array * 2 + Length of likes + Length of shareBy * 3 + views/3')}
{ where: { _id: arrayOfPost }}
)
my partial filter is deleting document, but user is not matching that requirement, am I using partial filter incorectly?
Thanks
const postSchema = new mongoose.Schema(
{
title: { type: String },
description: { type: String },
image: { type: String },
price: { type: String },
location: { type: String },
image: { type: Array },
author: {
type: String,
ref: 'User'
},
authorPremium: {
type: Boolean,
default: true,
index:true
},
reported: {
type: Boolean,
default: false
},
reportClear: {
type: Boolean,
default: false
}
},
{
timestamps: true
}
);
// users who are not premium will have posts deleted after 20 seconds
postSchema.index({ createdAt: 1 }, { expireAfterSeconds: 20, partialFilterExpression: { authorPremium: false } });
module.exports = mongoose.model('Post', postSchema);
partial filer should not allow the authorPremium which is true to be deleted, but only delete is authorPremium is false... please advise.
return from mongo index
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.posts"
},
{
"v" : 2,
"key" : {
"createdAt" : 1
},
"name" : "createdAt_1",
"ns" : "test.posts",
"expireAfterSeconds" : 120,
"background" : true
},
{
"v" : 2,
"key" : {
"authorPremium" : 1
},
"name" : "authorPremium_1",
"ns" : "test.posts",
"background" : true
},
{
"v" : 2,
"key" : {
"timestamps" : 1
},
"name" : "timestamps_1",
"ns" : "test.posts",
"expireAfterSeconds" : 20,
"background" : true
}
]
it seems when I use mongo cmd some of my old setting remained.. and some new? So how can I completly clear these old ttl settings when I am testing and ensure only the ones I want are there?
It looks like your .index(...) does not work because you already have old index on createdAt field and mongoose won't drop the old one. To synchronize the indexes with your schema you can use Model.syncIndexes
More on how .index() works and why .syncIndexes() was introduced can be found here.
I have a mongoose schema for categories
import mongoose from 'mongoose';
import { imageScheme } from './data.schemas';
mongoose.plugin(require('mongoose-delete'));
mongoose.plugin(require('mongoose-timestamp'));
const Schema = mongoose.Schema;
const catScheme = new Schema({
title: {
type: String
},
subTitle: {
type: String
},
description: {
type: String
},
images: [imageScheme],
icon: {
type: String
},
deleteAt: {
type: Date,
default: null
}
});
const Category = mongoose.model('Category',catScheme);
export default Category;
my image schema is located in another file
const imageScheme = new Schema({
imageCaption : {
type: String
},
imageFileName: {
type: String,
required: true
},
imagePath: {
type: String,
required: true
}
});
and when I am using the model for creating new category its adding the timestamp and deleted for my images array which means its loading the plugins ( mongoose-delete , mongoose-timestamp ) into the sub schema
HOW TO AVOID THAT ?
that is the result
{
"_id" : ObjectId("5d5a822f20179023e008f10c"),
"deleteAt" : null,
"deleted" : false,
"title" : "Eyes and Ears",
"description" : "here you will find all ppe to keep your eye 6 sharp",
"icon" : "glass.svg",
"images" : [
{
"_id" : ObjectId("5d5a822f20179023e008f10e"),
"deleted" : false,
"imageCaption" : "Eyes and Ears",
"imageFileName" : "67acca17-3fc8-416c-bc00-8273770b2115.jpeg",
"imagePath" : "resources/images/67acca17-3fc8-416c-bc00-8273770b2115.jpeg",
"updatedAt" : ISODate("2019-08-19T11:04:15.756Z"),
"createdAt" : ISODate("2019-08-19T11:04:15.756Z")
},
{
"_id" : ObjectId("5d5a822f20179023e008f10d"),
"deleted" : false,
"imageCaption" : "Eyes and Ears",
"imageFileName" : "9f1c5b1f-c1be-48f2-a9bc-8294930fd4c9.jpeg",
"imagePath" : "resources/images/9f1c5b1f-c1be-48f2-a9bc-8294930fd4c9.jpeg",
"updatedAt" : ISODate("2019-08-19T11:04:15.756Z"),
"createdAt" : ISODate("2019-08-19T11:04:15.756Z")
}
],
"updatedAt" : ISODate("2019-08-19T11:04:15.756Z"),
"createdAt" : ISODate("2019-08-19T11:04:15.756Z"),
"__v" : 0
}
It looks like you are plugging the mongoose-delete and mongoose-timestamp in the whole database.
Have you tried the example provided in the plugin pages?
catScheme.plugin(mongoose-timestamp)
catScheme.plugin(mongoose-delete)
I am using w2ui(http://w2ui.com/) plugin.
I am using the upload model.
fields: [
{ name: 'taskName', type: 'text', required: true},
{ name: 'taskDomain', type: 'text', required: true},
{ name: 'mailList', type: 'file', accept:'.txt',options: formoptions('you can only upload file that ext txt',['txt']), required: true}
],
function formoptions (placehold,allowExt){
options = {
selected : [], // selected array
placeholder : placehold,
max : 0,
maxSize : 0,
maxFileSize : 0,
maxWidth : 250,
maxHeight : 350,
maxDropHeight : 350,
silent : true,
renderItem : null,
style : '',
onClick : null,
onAdd : function (event){
s =this;
for(var i in event){console.log(i)}
event.onComplete=function (argument) {
if(!isAllowUpload(event.file.name,allowExt)){
//forbidden filetype
w2alert('just allow'+String(allowExt)+'!');
/***the question is here How do I remove this file***/
}
}
},
onRemove : null,
onMouseOver : null,
onMouseOut : null
};
return options;
}
I have some questions about using the w2ui upload model.
When users uploads a file, we need to check the file to ensure the file type is permitted. How can I exclude files of a forbidden type?
I have seen some similar questions related to this but have not found an answer.
I am attempting to create a Gallery in my Keystone Project that is similar to a post, where there will be a list of galleries and in it a gallery with a set of selected images:
var keystone = require('keystone'),
Types = keystone.Field.Types;
/**
* Gallery Model
* =============
*/
var Gallery = new keystone.List('Gallery', {
map: { name: 'name' },
autokey: { path: 'slug', from: 'name', unique: true }
});
Gallery.add({
name: { type: String, required: true},
published: {type: Types.Select, options: 'yes, no', default: 'no', index: true},
publishedDate: { type: Types.Date, index: true, dependsOn: { published: 'yes' } },
description: { type: String },
heroImage : { type: Types.Relationship, ref: 'Image' },
images : { type: Types.Relationship, ref: 'Image', many: true }
});
Gallery.defaultColumns = 'title, published|20%, publishedDate|20%';
Gallery.register();
I am able to create one gallery successfully - but any subsequent galleries throw the error:
There was an error saving your changes: insertDocument :: caused by ::
11000 E11000 duplicate key error index: site-name.galleries.$key_1 dup
key: { : null } (MongoError)
I am at a loss for what I need to change to this model to allow unique slugs for my galleries to be directly linked to etc.
Completely delete the model from MongoDB and restart. I typically see this error when making changes to a model with indexes that have been defined previously
with insert new item,you should set an default value for 'name', because name is set unique=true.
in my case, key is set to unique.
before:
MongoDB Enterprise > db.categories.save({_id: 89,name: 'xxx'})
WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error collection: sku.productcategories index: key_1 dup key: { : null }"
}
})
after:
MongoDB Enterprise > db.categories.save({_id: 89,name: 'xxx', key:'xx'})
WriteResult({ "nMatched" : 0, "nUpserted" : 1, "nModified" : 0, "_id" : 89 })