I created a collection called Stampest that stores a reference of an uploaded image and a title string, created by a user. Using the ostrio:autoform package.This package creates a collection called Images where all the user uploaded images are stored and hense referenced to/from.
When I query mongo in my terminal using
db.stampest.find({})
I get the entries
Which shows that there are documents in the database, in the Stampest Collection. But the PROBLEM is that when I look at the collection in Meteor Toys debug, it says its empty, and when I insert a document, in this case, the image and the title, the collection changes to 1 for a split second and geos back to 0. There are no error from the terminal or console
As a consequence, I cannot access these documents, what can I do?
This is the schema.js
Schemas = {};
Stampest = new Meteor.Collection('stampest');
Stampest.allow({
insert: function (userId, doc) {
return userId;
},
update: function (userId, doc, fields, modifier) {
// can only change your own documents
return doc.userId === userId;
},
remove: function (userId, doc) {
// can only remove your own documents
return doc.userId === userId;
}
});
Schemas.Stampest = new SimpleSchema({
title: {
type: String,
max: 60
},
picture: {
type: String,
autoform: {
afFieldInput: {
type: 'fileUpload',
collection: 'Images',
// uploadTemplate: 'uploadField' // <- Optional
// previewTemplate: 'uploadPreview' // <- Optional
}
}
}
});
Stampest.attachSchema(Schemas.Stampest);
The publish is like this:
Meteor.publish('stampest', function () {
return Stampest.find({author: this.userId}).fetch();
console.log(Stampest.find());
});
The user inserts the image and the title like this:
<template name="createStamp">
<div class="grid-block">
<div class="grid-container">
<div class="upload-img">
{{file.original.name}}
</div>
<div class="new-stamp-container">
{{> quickForm collection="Stampest" type="insert" id="insertStampForm" class="new-stamp-form"}}
</div>
</div>
</div>
</template>
From what I see in your code, you are returning an Array of db items and not a Cursor in your code.
If you take a look at https://docs.meteor.com/api/pubsub.html, you'll notice that regular publications return simple cursors or array of cursors but never your fetched data.
edit: also, the console.log in your publication will never be interpreted as it returns on the previous line.
Related
I want to update only the name field, the problem with the code I have is that if I update a document, all the mongo documents are updated.
As I update a document in specific, I must admit that I am new to this mongo so any help I thank you.
Client
updatename.html
<template name="updatename">
<form class="editor-container">
<input class=“save” type="text" id="card" value=“{{name}}”>
<button type="button" class=“save” id="save">save</button>
</form>
</template>
updatename.js
Template.updatename.events({
'click .save’: function (e, t) {
e.preventDefault();
FlowRouter.watchPathChange();
var name = FlowRouter.current().params._id;
var name = $('#card').val();
Meteor.call('name.update',name);
FlowRouter.go('/');
}
});
Server
name.js
Meteor.methods({
'name.update'( name) {
Name.update({
Name.update({},{ $set: { nam: name }},{multi:true})
});
}
});
I recommend few improvisations over your Meteor code.
Atleast use Title Case/ CamelCase for better readability of the template name and Meteor Methods for other developer.
use submit .formClassName instead of using click .save, also specifiy parameter name with sincerity like function (event, template)
When you updating document for logged user and not other user, as dmayo mentioned in the code use Name.update({_id: Meteor.userId()},{ $set: {nam: name}}), but there is no sense of specifying { multi: true } when you know that there is going to be only 1 record when you are updating. You can use { multi: true } when you desire to impact many records based on criteria that are definitely going to return more than 1 record.
use check(name, String) in Meteor.method call to ensure what you are sending to the server is eligible for further operations.
Use aldeed autoforms when you know there is no out of the box implementation and is going to be simple.
Below is the improvised code for better readability and up to standards
Client
update-name.html
<template name="UpdateName">
<form class="editorContainerForm">
<input type="text" id="card" value=“{{name}}”>
<button type="submit">Save</button>
</form>
</template>
update-name.js
Template.UpdateName.events({
'submit .editorContainerForm’: function (event, template) {
event.preventDefault();
FlowRouter.watchPathChange();
var name = FlowRouter.current().params._id;
var name = $('#card').val();
Meteor.call('updateName',name, function(error, response){
if(error){
// Show some BERT ERROR message for better user experience
// use "meteor add themeteorchef:bert" to add package
} else {
// Show some BERT SUCCESS message for better user experience
});
FlowRouter.go('/');
}
});
Server
name.js
Meteor.methods({
updateName( name ) {
check(name, String);
Name.update({ _id: Meteor.userId },{ $set: { name: name }});
// Use below code only if you know there can be multiple records for same ID
// Name.update({ _id: Meteor.userId },{ $set: { name: name }}, { multi: true });
}
});
In your name.js file (on the server) your mongo query is empty, so when mongo queries your database, it matches all of the documents/records.
Name.update(query, changes, options)
That is the format per the mongo docs. You need to have a unique identifier. Your form is saving a "name", and that's what you are passing to the Meteor.method, but you're not telling the method who's changing their name. If the user is logged in, then you can just use the meteor unique id Meteor.userId()
Name.update({_id: Meteor.userId()},{ $set: {nam: name}},{multi:true})
Also, your option multi:true says to update any and all documents that match the query. If in your original method as written, you had multi:false (the default) then only one document would have been updated (but probably not the one you wanted as the first match would have been updated because of your empty query field.
Mongo docs: https://docs.mongodb.com/manual/reference/method/db.collection.update/
Metor docs: https://docs.meteor.com/api/collections.html#Mongo-Collection-update
I'm trying to get return a list of users based on their accountActiveDate which is stored in a separate collection. If I console.log candidateUserIDByDate it returns the users in the correct order however when I return Meteor.users.find using the var candidateUserIDByDate its not sorted.
Path: sort.js
let sortCandidatesByDate = CandidateAccountStatus.find({}, {sort: {accountActiveDate: 1}}).fetch();
let candidateUserIDByDate = _.map(sortCandidatesByDate, function(obj) {
return obj.candidateUserId;
});
return Meteor.users.find({$and: [{_id: { $ne: Meteor.userId() }}, {_id: { $in: candidateUserIDByDate }}]});
I think a (probably hackish) solution would be, returning the CandidateAccountStatus and inside the loop, using another helper to return the correct user like this:
Template helpers:
status: function(){
//you might want to do {$ne: {Meteor.userId()}} for the correct field
//in your selector if you don't want currentUser status
return CandidateAccountStatus.find({}, {sort: {accountActiveDate: 1}})
},
statusUser: function(){
//change correctField to how you save the userId to
//your CandidateAccountStatus schema
return Meteor.users.findOne({_id: this.correctField})
}
HTML
{{#each status}}
{{#with statusUser}}
<!-- You have the user object here -->
{{_id}} <!-- gives the userId -->
{{/with}}
{{/each}}
I'm building a very small Meteor application simply to get a better understanding of Autoform and CollectionFS, and their use together. I currently have everything set up with the following packages:
iron:router, aldeed:autoform, aldeed:collection2, cfs:standard-packages,
cfs:filesystem, cfs:autoform
I have a sample Mongo Collection assigned to "Books" set up with a SimpleSchema attached, with fields from the demo like title and author. The corresponding code for the file upload is:
fileId: {
type: String,
autoform: {
afFieldInput: {
type: "cfs-file",
collection: "images"
}
}
}
The FS.Collection code is:
Images = new FS.Collection("images", {
stores: [new FS.Store.FileSystem("images", {path: "~/uploads"})]
});
This is in conjunction to a quickform: {{> quickForm collection="Books" id="insertBookForm" type="insert"}}
The insert is fine, and I can iterate over the documents and display the various fields using spacebars and a helper function called "books", like so:
{{#each books}}
<li>{{title}} by {{author}}</li>
{{/each}}
I can also iterate over images uploaded to the FS.Collection with a helper returning the entire collection called "files," and looping over them like so:
{{#each files}}
<img src="{{this.url}}" />
{{/each}}
The issue I'm having is linking the two together. I want to be able to do something along the lines of:
{{#each books}}
<li>{{title}}, by {{author}} <img src="The-Corresponding-Image}}" /></li>
{{/each}}
Obviously not that exact layout, but I basically just want to be able to print images with their corresponding titles and authors to be able to use autoform with collectionfs for my needs.
I'm stuck trying to retrieve the fileId from a specific document in the Books collection, and then plugging that into an Images.findOne({fileId: fileId}) and linking the two together.
Can anyone point me in the right direction?
I was able to figure it out thanks to Ethaan's guidance. What I had to do was the following:
Autoform Hook:
AutoForm.hooks({
insertBookForm: {
after: {
insert: function(error, result, template) {
insertedFile = Books.findOne(result).fileId;
Images.update({_id: insertedFile}, {$set: {'book': result}});
}
}
}
});
I set a field of 'book' to the _id of the document being inserted (stored in the result parameter) right after it was inserted.
This is my corresponding HTML:
{{#each books}}
<li>{{title}} by {{author}}</li>
{{#with files}}
<img src="{{this.url}}" />
{{/with}}
{{/each}}
And my helpers:
Template.layout.helpers({
books: function () {
return Books.find({});
},
files: function() {
return Images.findOne({book: this._id});
}
});
i have an "back end" application which write in MongoDb (in database i have _id: with ObjectId("13f6ea...002")) i use meteor app to show information. Everything was good i displays list of information with {{#each}}. But when i wanted show one element with '_Id' nothing works.
I read this issue and adapt my code to get right root, But i can't display anything on the page. I tried to write Template helpers but it didn't helped
Db record:
{
_id: ObjectId("13f6ea...002"),
url: "foo",
title: "bar",
published: "2014-08-22 03:26:21 UTC",
image: "foo.jpg",
summary: "foo ",
categories: [
"F",
"B"
],
...
}
Route:
this.route('news', {
path: '/news/:_id',
template: 'news',
waitOn: function () {
var id = this._id;
Meteor.subscribe('news', id);
},
data: function() {
var id = this.params._id;
return News.findOne({ _id: Meteor.Collection.ObjectID(this.params._id)});
},
action : function () {this.render();},
});
Publish
Meteor.publish('news', function(id) {
return News.find({_id: id});
});
Template which redirect to unique post
<h4>{{title}}</h4>
And template is just {{news}}
How can i fix this?
UPDATE
My solutions to fix that:
router.js
waitOn: function () {
var id = this._id;
Meteor.subscribe('News', id);
},
data: function() {
return News.findOne(new Meteor.Collection.ObjectID(this.params._id));
},
and in template
<a href="news/{{_id._str}}">
Navigate to the appropriate url in your browser (i.e. localhost:3000/news/[_id]), open the console and enter:
Router.current().data()
That will show you the data context of the current route. Either it returns nothing, in which case there is a fundamental problem with your News.findOne query as it's returning nothing, or (more likely) it returns the required document.
In the latter case, as far as I can see there is no news property within that document, which is why it isn't rendering anything. If you change {{news}} to {{url}} or {{summary}} I would imagine it would render the requested property.
If by {{news}} you're trying to render the entire document, then (aside from the fact that it will render as something like [Object]) you need to make news a property of the object returned by your data function:
return {
news: News.findOne({ _id: Meteor.Collection.ObjectID(this.params._id)});
};
Getting Document with _id :
In the .js file under events, Say on click event and Collection EventList :-
'Submit form' : function () {
var id = this._id;
return EventList.find({_id : id}).fetch();
}
This would return the object for the id. In my Case, I am displaying a field for all documents in Collection. User selects a record and clicks Submit, which fetches all Document fields and displays to the User
Running on Ubuntu
Data.js
//Collections
Database = new Meteor.Collection('data');
if (Meteor.isClient) {
Template.main.data = function () {
var c = Database.find();
return c;
};
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
data.html
<head>
<title>data</title>
</head>
<body>
{{> main}}
</body>
<template name="main">
{{data}}
</template>
I inserted into the db using mongo:
> db.Database.insert({title: 'ShouldWork'});
> db.Database.find();
{ "_id" : ObjectId("5296403855ee6e1350b35afb"), "title" : "ShouldWork" }
Yet when I run the site it just returns [object Object]..
There should be autopublish on and insecure,
This has become quite the roadblock for me to clear in learning the framework.
This is expected. This is because the results of .find() are always a cursor and have multiple objects.
You have to decide which one you want or if you want to loop through each one.
1) You want to use one result:
var c = Database.findOne();
or 2) You want to iterate through each one:
{{#each data}}
{{title}}
{{/each}}
Additionally be sure to use the property of {{data}} because {{data}}, even with findOne is still an [Object object]. You should use something like {{data.title}} instead depending on the property you want to use.
How to access data in Mongo DB from html ?
First of all you need to have the Mongo DB instance present in global variable i:e it must be declared in any .js file as below. It is not part of client or server code
Say we create a Collection of Events in one of the js files.
EventList = new Mongo.Collection('Events');
Now, in order to access all the objects from HTML, we would need a Helper function inside client in our .js file. Below is Helper used:-
Template.viewEvent.helpers ({
//NOTE : 'event' is the name of variable from html template
'event' : function () {
//returns list of Objects for all Events
return EventList.find().fetch();
}
'users' : function () {
//returns reference to Document for all users
return UserList.find().fetch();
}
});
Just left to Display content on .html:-
Say EventList Collection has fields Event_Name, Event_Date. Below would be the html template code
<template name="viewEvent">
<h2>View Event</h2>
<!-- Iterate on all Objects fetched by the Helper Class-->
{{#each event}}
{{Event_Name}} : {{Event_Date}}
{{/each}}