I am trying to implement users following users and I have
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
name: String,
following: [{
type: Schema.Types.ObjectId,
ref: 'User'
}]
});
var User = mongoose.model('User',UserSchema);
So now, as a user I want get a list of my followers.
You could run a complex query to get your followers, however it's much easier to store followers in the document too:
var UserSchema = new Schema({
name: String,
followers: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
following: [{
type: Schema.Types.ObjectId,
ref: 'User'
}],
});
This requires a bit more work on updates, however it pays off on reads (which happen more often than updates).
Related
Basically... I have something of the following type: record<string, User> (aka Map<String,User>). Basically, an object that can have any field, as long as it is an user.
How do I create an Schema that validates that?
There is an older question that seems to ask the same thing Can SimpleSchema express "object with custom keys and specific schema for values"? , however being asked for an older version of this library.
The accepted answer assumes the usage of Custom Validators
https://github.com/longshotlabs/simpl-schema#type
Another SimpleSchema instance, meaning Object type with this schema
const userSchema = new SimpleSchema({
username: {
type: String,
// For accounts-password, either emails or username is required, but not both. It is OK to make this
// optional here because the accounts-password package does its own validation.
// Third-party login packages may not require either. Adjust this schema as necessary for your usage.
optional: true,
},
emails: {
type: Array,
// For accounts-password, either emails or username is required, but not both. It is OK to make this
// optional here because the accounts-password package does its own validation.
// Third-party login packages may not require either. Adjust this schema as necessary for your usage.
optional: true,
},
'emails.$': {
type: Object,
},
'emails.$.address': {
type: String,
regEx: SimpleSchema.RegEx.Email,
},
'emails.$.verified': {
type: Boolean,
},
// Use this registered_emails field if you are using splendido:meteor-accounts-emails-field / splendido:meteor-accounts-meld
registered_emails: {
type: Array,
optional: true,
},
'registered_emails.$': {
type: Object,
blackbox: true,
},
createdAt: {
type: Date,
},
profile: {
type: Schema.UserProfile,
optional: true,
},
// Make sure this services field is in your schema if you're using any of the accounts packages
services: {
type: Object,
optional: true,
blackbox: true,
},
// DISCLAIMER: This only applies to the first and second version of meteor-roles package.
// https://github.com/Meteor-Community-Packages/meteor-collection2/issues/399
// Add `roles` to your schema if you use the meteor-roles package.
// Option 1: Object type
// If you specify that type as Object, you must also specify the
// `Roles.GLOBAL_GROUP` group whenever you add a user to a role.
// Example:
// Roles.addUsersToRoles(userId, ["admin"], Roles.GLOBAL_GROUP);
// You can't mix and match adding with and without a group since
// you will fail validation in some cases.
roles: {
type: Object,
optional: true,
blackbox: true,
},
// Option 2: [String] type
// If you are sure you will never need to use role groups, then
// you can specify [String] as the type
roles: {
type: Array,
optional: true,
},
'roles.$': {
type: String,
},
// In order to avoid an 'Exception in setInterval callback' from Meteor
heartbeat: {
type: Date,
optional: true,
},
});
const someOtherSchema = new SimpleSchema({
useDocument: {
type: userSchema
},
});
I have a CosmosDB setup using the Mongo API. I have a collection with a hashed shard on one of the field of the document. When I run commands like db.collection.remove or db.collection.deleteMany I get the following error.
Command deleteMany failed: query in command must target a single shard key.: {"message":"Command deleteMany failed: query in command must target a single shard key."}
I'm not sure how can I mention a shard key as part of the query considering I want the query to run across all the shards.
You need to provide shard key when you want to run commands like db.collection.remove or db.collection.deleteMany.
For example :
My data source as below:
[
{
"id" : "2",
"name" : "b"
},
{
"id" : "1",
"name" : "a"
}
]
And my shared key is "/name". Use db.coll.deleteMany({"name":"a"}) to delete specific shard.
Hope it helps you.
It should be ShardKey which you have chosen when you created cosmosDb collection.
FilterDefinition<Product> filter = Builders<Product>.Filter.Eq("id", 2);
=== 2 is my shardKey
await this._dbContext.GetProducts.DeleteOneAsync(filter);
return RedirectToAction("Index");
Kindly refer an image below , how does it look like in CosmosDB
Shard Key(Partition Key) has to be provided during specification of schema model in the code. Once its provided, we can perform regular operation like save, update and delete as usual.
Example:
const mySchema = new Schema({
requestId: { type: String, required: true },
data: String,
documents: [{ docId: String, name: String, attachedBy: String }],
updatedBy: {
type: {
name: { type: String, required: true },
email: { type: String, required: true },
}, required: true
},
createdDate: { type: Date, required: true },
updatedDate: { type: Date },
}, { shardKey: { requestId: 1 } }
);
In the above code we specified requestId as Shard Key, now we can perform any mongo operations
Example:
let request:any = await myModel.findById(requestId);
request.data ="New Data";
await request.save();
Hope that helps.
This works with all Mongo operations
I'm trying to send some data to servlet using backbone js and i want to retrieve that data to backbone.js view. Here i mentioned my model and collection code. Please help me.
ContactManager.Models.Contact = Backbone.Model.extend({
defaults: {
name: null,
tel: null,
email: null,
address:null,
avatar: null
},
url: "/servlet1",
initialize: function() {
this.set('avatar','phone.png');
},
});
ContactManager.Collections.Contacts = Backbone.Collection.extend({
model: ContactManager.Models.Contact
});
I'm getting the error "_id is not allowed by the schema" when trying to use an autoform to update a collection via a ValidatedMethod.
As far as I can see from this example and the official docs there is no expectation for my schema to include the _id field, and I wouldn't expect to be updating the id from an update statement, so I have no idea why this error is happening.
If I switch from using the validated method to writing directly to the collection (with a schema attached to the collection that doesn't have the id in) everything works as expected, so I'm assuming the issue is with my the validate in my ValidatedMethod.
Any idea what I'm doing wrong?
Template: customer-edit.html
<template name="updateCustomerEdit">
{{> quickForm
collection="CustomerCompaniesGlobal"
doc=someDoc
id="updateCustomerEdit"
type="method-update"
meteormethod="CustomerCompanies.methods.update"
singleMethodArgument=true
}}
</template>
Template 'code behind': customer-edit.js
Template.updateCustomerEdit.helpers({
someDoc() {
const customerId = () => FlowRouter.getParam('_id');
const instance = Template.instance();
instance.subscribe('CustomerCompany.get', customerId());
const company = CustomerCompanies.findOne({_id: customerId()});
return company;
}
});
Update Validated Method:
// The update method
update = new ValidatedMethod({
// register the name
name: 'CustomerCompanies.methods.update',
// register a method for validation, what's going on here?
validate: new SimpleSchema({}).validator(),
// the actual database updating part validate has already been run at this point
run( newCustomer) {
console.log("method: update");
return CustomerCompanies.update(newCustomer);
}
});
Schema:
Schemas = {};
Schemas.CustomerCompaniesSchema = new SimpleSchema({
name: {
type: String,
max: 100,
optional: false
},
email: {
type: String,
max: 100,
regEx: SimpleSchema.RegEx.Email,
optional: true
},
postcode: {
type: String,
max: 10,
optional: true
},
createdAt: {
type: Date,
optional: false
}
});
Collection:
class customerCompanyCollection extends Mongo.Collection {};
// Make it available to the rest of the app
CustomerCompanies = new customerCompanyCollection("Companies");
CustomerCompaniesGlobal = CustomerCompanies;
// Deny all client-side updates since we will be using methods to manage this collection
CustomerCompanies.deny({
insert() { return true; },
update() { return true; },
remove() { return true; }
});
// Define the expected Schema for data going into and coming out of the database
//CustomerCompanies.schema = Schemas.CustomerCompaniesSchema
// Bolt that schema onto the collection
CustomerCompanies.attachSchema(Schemas.CustomerCompaniesSchema);
I finally got to the bottom of this. The issue is that autoform passes in a composite object that represents the id of the record to be changed and also a modifier ($set) of the data, rather than just the data itself. So the structure of that object is along the lines of:
_id: '5TTbSkfzawwuHGLhy',
modifier:
{
'$set':
{ name: 'Smiths Fabrication Ltd',
email: 'info#smithsfab.com',
postcode: 'OX10 4RT',
createdAt: Wed Jan 27 2016 00:00:00 GMT+0000 (GMT Standard Time)
}
}
Once I figured that out, I changed my update method to this and everything then worked as expected:
// Autoform specific update method that knows how to unpack the single
// object we get from autoform.
update = new ValidatedMethod({
// register the name
name: 'CustomerCompanies.methods.updateAutoForm',
// register a method for validation.
validate(autoformArgs) {
console.log(autoformArgs);
// Need to tell the schema that we are passing in a mongo modifier rather than just the data.
Schemas.CustomerCompaniesSchema.validate(autoformArgs.modifier , {modifier: true});
},
// the actual database updating part
// validate has already been run at this point
run(autoformArgs)
{
return CustomerCompanies.update(autoformArgs._id, autoformArgs.modifier);
}
});
Excellent. Your post helped me out when I was struggling to find any other information on the topic.
To build on your answer, if for some reason you want to get the form data as a single block you can use the following in AutoForm.
type="method" meteormethod="myValidatedMethodName"
Your validated method then might look something like this:
export const myValidatedMethodName = new ValidatedMethod({
name: 'Users.methods.create',
validate(insertDoc) {
Schemas.NewUser.validate(insertDoc);
},
run(insertDoc) {
return Collections.Users.createUser(insertDoc);
}
});
NB: The Schema.validate() method then requires an Object, not the modifier as before.
I'm unclear if there are any clear advantages to either method in general.
The type="method-update" is obviously the way you want to go for updating documents because you get the modifier. The type="method" seems to be the best way to go for creating a new document. It would likely also be the best option in most cases where you're not intending to create a document from the form data.
I'm creating a form using cfs:autoform to capture a photo and caption from submitted on the client like this:
Photos = new Mongo.Collection("photos");
Photos.attachSchema(new SimpleSchema({
userId:{
type: String,
autoValue:function(){return this.userId},
},
userName:{
type: String,
autoValue:function(){return Meteor.users.find({_id: this.userId}).username},
},
groupMembers: {
type: String
},
comments: {
type: String
},
fileId: {
type: String
}
}));
I've gotten the code to successfully capture and fill in the userId, as well as the comment and uploaded photo, but I can't seem to get it to capture the username.
It's most likely because you're using find instead of findOne. Since find returns a cursor and not a single document you can't access the username value, because it's not a property of the cursor. If you change it to findOne it should work.
userName:{
type: String,
autoValue:function(){return Meteor.users.findOne({_id: this.userId}).username},
}