Looking to access mongoose array of strings - mongodb

I am able to access all elements from my schema except for the array thats where it gets tricky for me. when I upload a pic and i use the developers console to see what link the image has it says " /lock.png " something like that and it does not show the picture just load the pic properly. So basically I need help saving the array elements and then loading them for the images:[String]
thanks
app.js
var postSchema = new mongoose.Schema({
title:String,
price:Number,
name: String,
image: String,
images: [String],
desc: String
})
app.post("/posts", function(req, res) {
//get data from and add to posts array
var title = req.body.title;
var price = req.body.price;
var image = req.body.image;
var desc = req.body.desc;
var images = req.body.images;
var newPost = { title: title, price: price, images: images, image: image, desc: desc};
//create new post and save to database
postModel.create(newPost, function(err, newlyCreated) {
if(err){
console.log("error with new post");
}else{
res.redirect("/posts");
}
});
//posts.unshift(newPost);
inside my ejs file
<input name="images" class="uploadFile btn btn-primary btn-block" type="file" multiple id="gallery-photo-add" placeholder="Choose File" >
<% posts.forEach(function(post) { %>
<div class = "row">
<div class ="col-xs-8">
<p><%= post.title %></p>
</div>
<div class ="col-xs-4">
<p>$<%= post.price %></p>
</div>
</div>
<% if(post.image === ""){ %>
<% }else { %>
<img class="img-rounded img-responsive half img-thumbnail" src="<%= post.image %>">
<% } %>
<img class="img-rounded img-responsive half img-thumbnail" src="<%= post.images %>">
<p><%= post.desc%></p>
<p>
More Info
</p>
<% }); %>
<script type="text/javascript">
$(function() {
// Multiple images preview in browser
var imagesPreview = function(input, placeToInsertImagePreview) {
if (input.files) {
var filesAmount = input.files.length;
for (i = 0; i < filesAmount; i++) {
var reader = new FileReader();
reader.onload = function(event) {
$($.parseHTML('<img class="img-rounded img-responsive img-thumbnail">')).attr('src', event.target.result).appendTo(placeToInsertImagePreview);
}
reader.readAsDataURL(input.files[i]);
posts.images[i].set(i, input.files[i]);
}
}
};
$('#gallery-photo-add').on('change', function() {
imagesPreview(this, 'div.gallery');
});
});
</script>
I just get this image
this is what comes up in my database
{ "_id" : ObjectId("57550dfd1fdfa6f701be755f"), "title" : "", "price" : 5555, "desc" : "", "images" : [ "city-1026227_960_720.jpg" ], "__v" : 0 }

I just made a simple working example that outputs an image in an array that was saved to the database. I don't see what you are doing doing for res.render. I mean in my example the string was saved to the database and it displays an img from a remote server at http://placehold.it/350x150
var express = require("express"),
app = express(),
mongoose = require("mongoose"),
ejs = require("ejs");
mongoose.connect("mongodb://localhost/arrays");
app.set("view engine" , "ejs")
var postSchema = mongoose.Schema({
title : String,
images : [String]
})
var Post = mongoose.model("posts", postSchema);
Post.remove({},function(err, data){
console.log("removed")
})
Post.create({title : "test", images : ["http://placehold.it/350x150", "two"]}, function(err, data){
if(err) throw err;
console.log(data);
})
app.get("/", function(req, res){
Post.findOne({"title" : "test"}, function(err, data){
if(err) throw err;
res.render("array", {data: data})
})
})
app.listen(3000, function(){
console.log("listening on 3000")
})
array.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>arrays</title>
</head>
<body>
<img src="<%= data.images %>" alt="">
</body>
</html>
EDIT: you could also try something like src="localhost:port/<%= post.images[0] %> and I'm wondering if your src="<%= post.image %>" works because if it doesn't your problem could be the way your loading the files and not the way you are using arrays.

Related

Page won't redirect when uploading to db with multer

I'm trying to upload (update acutally) an image to a db and then redirect to profile page, i tried everything and the photo is updated successfully in the db but page wont redirect.
If i dont attach an image everything is ok and user gets redirected.
If i do attach an image user just stays on form page, no errors pop up, page just gets refreshed (photo gets updated in db successfully)
post route
var store = require("./multer");
router.post("/:username/edit", isUser, personalContent, store.single("profilePic"), async (req, res) => {
try {
if (req.file) {
await User.updateOne(
{ username: req.user.username },
{
username: req.params.username,
dateOfBirth: req.body.date,
filename: req.file.originalname,
contentType: req.file.mimetype,
imageBase64: fs.readFileSync(req.file.path).toString("base64"),
},
{ upsert: true }
);
} else {
await User.updateOne(
{ username: req.user.username },
{
username: req.params.username,
dateOfBirth: req.body.date,
},
{ upsert: true }
);
}
res.redirect("/profile/" + req.params.username + "?msg=Profile updated successfully");
} catch (err) {
console.log(err);
res.redirect("/profile/" + req.params.username + "?msg=Error while updating profile");
}
});
ejs form
<form action="/profile/<%= user.username %>/edit" enctype="multipart/form-data" method="POST">
<% if(error){ %> <%= error %> <% } %> <% if(msg){ %> <%= msg %> <% } %>
<div>
<label for="username">Username: </label>
<input type="text" name="username" value="<%= user.username %>" disabled />
</div>
<div>
<label for="date">Date of birth: </label>
<input type="date" name="date" required value="<%= user.dateOfBirth.toISOString().split("T")[0] %>" />
</div>
<div>
<label for="profpic">Profile picture:</label>
<input type="file" name="profilePic" />
<div>
<% if(user.imageBase64){ %>
<img src="data:<%=user.contentType%>;base64,<%=user.imageBase64%>" alt="" style="height: 3rem" />
<% }else{ %> Add profile picture <% } %>
</div>
</div>
<button type="submit">Submit</button>
</form>
multer.js
const multer = require("multer");
//set storage
var storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "uploads");
},
filename: (req, file, cb) => {
cb(null, file.fieldname + "-" + Date.now());
},
});
module.exports = store = multer({ storage: storage });
The issue was with LiveServer chrome extension, it was messing something up with redirects. Now this question seems stupid to me but if someone stumbled upon this I hope I could help

How to read data from mongodb by input value and display it using ejs?

I am trying to search mongodb on a post request for all products in my database. Everything is working except the post request. The request goes through but no data is given back. I do not see a problem with the database.
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const app = express();
app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static("public"));
mongoose.connect(
"mongodb+srv://x:origisgood#cluster0.d6rzu.mongodb.net/productsDB?
retryWrites=true&w=majority",
{
useNewUrlParser: true,
useUnifiedTopology: true,
}
);
const productsSchema = {
name: String,
price: Number,
img: String,
};
const Product = mongoose.model("product", productsSchema);
app.get("/", function (req, res) {
res.send(__dirname + "/index.html");
});
app.post("/", function (req, res) {
const productName = req.body.productName;
Product.find({ name: productName }, function (err, foundProducts) {
res.render("home", {
name: foundProducts.name,
price: foundProducts.price,
img: foundProducts.img,
});
});
});
app.listen(3001, function () {
console.log("Server started successfully");
});
index.html to be displayed before everything else
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8" />
<title>X</title>
</head>
<body>
<form action="/" method="post">
<input
type="text"
name="productName"
placeholder="Search for a product"
/>
<button type="submit" name="Search">Search</button>
</form>
</body>
</html>
home.ejs to be displayed when a product is searched up
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>X</title>
</head>
<body>
<h1><%= name %></h1>
<% var imgwostr = img; %>
<% imgwostr = str.replace(/^"|"$/g, ""); %>
<img src="<%= imgwostr %>" alt="">
<p><%= price %></p>
</body>
</html>
Your problem is that the db returns a list of documents that you treat as one.
Your foundProducts object is actually an array of type Product, even if there is only one product it is still an array which means that if you want to get the value back you would need to specify an index of the item you want to get.
Something like this should work:
Product.find({ name: productName }, function (err, foundProducts) {
const product = foundProducts[0];
if (!product) {
res.render('notfound');
}
res.render("home", {
name: product.name,
price: product.price,
img: product.img,
});
}
Notice that if the product is not found you would need to render another page because you will have nothing to display.

Meteor + React: Append response to DOM after a Meteor.call?

I am super new to React and quite new to Meteor.
I am doing a Meteor.call to a function ('getTheThing'). That function is fetching some information and returns the information as a response. In my browser I can see that the method is returning the correct information (a string), but how do I get that response into the DOM?
(As you can see, I have tried to place it in the DOM with the use of ReactDOM.findDOMNode(this.refs.result).html(response);, but then I get this error in my console: Exception in delivering result of invoking 'getTheThing': TypeError: Cannot read property 'result' of undefined)
App = React.createClass({
findTheThing(event) {
event.preventDefault();
var username = ReactDOM.findDOMNode(this.refs.textInput).value.trim();
Meteor.call("getTheThing", username, function(error, response){
console.log(response);
ReactDOM.findDOMNode(this.refs.result).html(response);
});
ReactDOM.findDOMNode(this.refs.textInput).value = "";
},
render(){
return(
<div className="row">
<div className="col-xs-12">
<div className="landing-container">
<form className="username" onSubmit={this.findTheThing} >
<input
type="text"
ref="textInput"
placeholder="what's your username?"
/>
</form>
</div>
<div ref="result">
</div>
</div>
</div>
);
}
});
this is under the different context, thus does not contain the refs there. Also, you cannot set html for the Dom Element. You need to change into Jquery element
var _this = this;
Meteor.call("getTheThing", username, function(error, response){
console.log(response);
$(ReactDOM.findDOMNode(_this.refs.result)).html(response);
});
Though i recommend you to set the response into the state and let the component re-rendered
For a complete React way
App = React.createClass({
getInitialState() {
return { result: "" };
},
shouldComponentUpdate (nextProps: any, nextState: any): boolean {
return (nextState['result'] !== this.state['result']);
},
findTheThing(event) {
event.preventDefault();
var username = ReactDOM.findDOMNode(this.refs.textInput).value.trim();
Meteor.call("getTheThing", username, function(error, response){
console.log(response);
_this.setState({ result: response });
});
ReactDOM.findDOMNode(this.refs.textInput).value = "";
},
render(){
return(
<div className="row">
<div className="col-xs-12">
<div className="landing-container">
<form className="username" onSubmit={this.findTheThing} >
<input
type="text"
ref="textInput"
placeholder="what's your username?"
/>
</form>
</div>
<div ref="result">{this.state['result']}</div>
</div>
</div>
</div>
);
}
});

How to get an image from gridFS in Meteorjs

I am using the gridFS package in MeteorJS.
What system does is upload a product with an image a title, a category and a price. This gets saved in the products collection.
With a template helper I can get a product from the db with it's title {{title}} and price {{price}}. But I'm stuck getting the image using the reference in de the product document.
Can anyone help me with that?
<template name="product">
<div class="small-6 medium-3 columns end">
<div class="product-container">
<div class="image-container">
{{#with image}}
<img src="{{this.url}}" class="product-image" alt="" />
{{/with}}
</div>
<div class="product-details">
<div class="product-title">
{{title}}
</div>
<div class="product-price">
{{price}}
</div>
<div class="product-buttons">
<span class="icon-heart"></span>
<span class="icon-repost"></span>
<span class="icon-plus"></span>
</div>
</div>
</div>
</div>
</template>
<template name="home">
{{#each products}}
{{> product}}
{{/each}}
</template>
Products = new Mongo.Collection("products");
var productImagesStore = new FS.Store.FileSystem('productImages', {
path: '~/uploads/full'
});
productImages = new FS.Collection('productImages', {
stores: [productImagesStore]
});
productImages.allow({
insert: function () {
return true;
},
update: function () {
return true;
},
remove: function () {
return true;
},
download: function () {
return true;
}
});
if (Meteor.isClient) {
// This code only runs on the client
Template.home.helpers({
products: function () {
return Products.find({});
},
image:function(){
return productImages.findOne({'metadata.productId':this._id})
}
});
Template.add.helpers({
categories: function(){
return categories.find({});
}
});
Template.add.events({
"submit form": function(event, template) {
event.preventDefault();
var file = $('#file').get(0).files[0],
fsFile = new FS.File(file),
productData = {
title:$('#title').val(),
price:$('#price').val(),
category:$('#category').val()
}
Products.insert(productData,function(err,result){
if(!err){
fsFile.metadata = {
productId:result, //we use metadata to refer the recent object id with the product images
}
productImages.insert(fsFile,function(err,result){
if(!err){
console.log("New images inserted")
}
});
}
});
}
});
}
You can store the reference on the productImages collection like this.
var file = $('#file').get(0).files[0],
fsFile = new FS.File(file),
productData = {
title:$('#title').val(),
price:$('#price').val(),
category:$('#category').val()
}
Products.insert(productData,function(err,result){
if(!err){
fsFile.metadata = {
productId:result, //we use metadata to refer the recent object id with the product images
}
productImages.insert(fsFile,function(err,result){
if(!err){
console.log("New images inserted")
}
});
}
});
This is the same insert but a little bit more cleaner
Now you can use the helper and the this context like this.
HTML
{{#each products}}
{{title}}
{{price}}
{{#with image}}
IMG URL:{{this.url}}
<img src="{{this.url}}" />
{{/with}}
{{/each}}
JS(Helpers)
Template.example.helpers({
products:function(){
return Products.find()
},
image:function(){
return productImages.findOne({'metadata.productId':this._id})
}
})

Meteor: Subscribed Colletion doesn't update automatically (Reactivity)

I'm facing the problem that adding data to a subscribed Collection doesn't automatically refresh the shown elements of a collection. If I add a new element the element show's up for a second and then disappears! Refreshing the browser (F5) and the new element shows up.
I put the subscription into Meteor.autorun but things kept beeing the same.
lists.html (client):
<<template name="lists">
<div class="lists col-md-12" {{!style="border:1px red solid"}}>
<!-- Checklist Adder -->
<form id="list-add-form" class="form-inline" role="form" action="action">
<div class="col-md-6">
<input class="form-control" id="list-name" placeholder="Neue Liste" required="required"/>
</div>
<button type="submit" class="btn btn-primary" id="submit-add">
<span class="glyphicon glyphicon-plus-sign"></span>
Neue Liste
</button>
</form>
<!-- Checklist Ausgabe -->
<ul>
<br/>
{{#each lists}}
<li style="position: relative;" id="{{this._id}}" data-id="{{_id}}" class="clickOnList">
<!--<input type="button" class="deleteLists" id="{{this._id}}" value="-" style="z-index: 999;"/> -->
<span id="{{this._id}}" data-id="{{_id}}" style="padding-left: 10px; vertical-align:middle;">{{this.name}}</span>
<form id="changerForm_{{_id}}" class="changeList-name-form" data-id="{{_id}}" style="visibility: hidden; position: absolute; top:0;">
<input id="changerText_{{_id}}" type="text" class="list_name" data-id="{{_id}}" value="{{this.name}}" />
</form>
{{#if ownerOfList this._id}}
<a data-toggle="modal" class="userForListModal" id="{{this.name}}" data-id="{{this._id}}" data-target="#userForListModal">
<span class="glyphicon glyphicon-user" id="{{this.name}}" style="color:black;"data-id="{{this._id}}"></span><span style="color:black;" id="{{this.name}}" data-id="{{this._id}}" style="font-size: small; vertical-align: super">{{memberCount this._id}}</span></a>
<div class="deleteLists" id="dLBtn_{{_id}}" data-id="{{this._id}}" style="float: right; padding-right: 5px; padding-top: 1px; visibility: hidden;">
<span class="deleteLists glyphicon glyphicon-minus-sign" data-id="{{this._id}}"></span>
</div>
{{else}}
<a class="userForListModal">
<span class="glyphicon glyphicon-user" style="color:black;"></span><span style="color:black;" style="font-size: small; vertical-align: super">{{memberCount this._id}}</span></a>
{{/if}}
<!-- <button type="submit" class="deleteLists btn btn-default btn-xs" id="dLBtn_{{_id}}" data-id="{{this._id}}" style="float: right;" > -->
</button>
</li>
{{/each}}
</ul>
</div>
<div class="modal fade" id="userForListModal" >
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="userForListModalLabel"></h4>
</div></template>
<div class="modal-body col-md-12">
<div id="userForListModalUsers">
</div>
<p>Neuen Benutzer zur Checkliste hinzufügen:</p>
<form id="list-addUser-form" class="form-inline" role="form" action="action">
<div class="col-md-12">
<div class="col-md-6">
{{inputAutocomplete settings id="name-list-addUser" class="input-xlarge" placeholder="Benutzer Name" required="required"}}
</div>
<div class="col-md-6">
<button type="submit" class="btn btn-secondary" id="submit-list-addUser">
<span class="glyphicon glyphicon-plus-sign"></span>
Benutzer hinzufügen
</button>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<div id="userForListModalerrorMessage" style="color:red; display: none; text-align:left"></div><button type="button" class="btn btn-default" data-dismiss="modal">Schließen</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</template>
<template name="userPill">
<span class="label" style="color:black">{{username}}</span>
lists.js (client):
Template.lists.lists = function(){ return Lists.find(); }
Lists = new Meteor.Collection("lists");
Deps.autorun(function() {
Meteor.subscribe('lists');
})
lists.js
var activeListName = "";
var activeListID = "";
Template.lists.lists = function()
{
return Lists.find();
}
Template.lists.memberCount = function(id)
{
var count = "";
Meteor.call("listMemberCount", id, function(error,result)
{
if (error) {
console.log("List not initialized:" + error.reason);
}
else
{
Session.set("countMember_"+id,result);
}
});
return Session.get("countMember_"+id);
}
Template.lists.ownerOfList = function(id)
{
return ( Meteor.userId() == Lists.findOne({_id : id}).owner);
}
Template.lists.settings = function()
{
return {
position: "top",
limit: 5,
rules: [
{
token: '',
collection: Meteor.users,
field: "username",
template: Template.userPill
}]
}
}
Template.lists.events({
'submit #list-add-form' : function(e, t) {
/* Checklisten ausgeben */
e.preventDefault();
var name = t.find('#list-name').value;
var id = new Meteor.Collection.ObjectID().valueOf();
var id_block = new Meteor.Collection.ObjectID().valueOf();
Lists.insert({_id : id, name : name, owner : Meteor.userId()});
Meteor.users.update({_id : Meteor.userId()}, {$addToSet :{lists : id}});
Listitems.insert({_id : id_block, name : "", items: []});
Lists.update(id, {$addToSet : {items : id_block}});
},
'click .clickOnList' : function(e)
{
/* Eventhandler fuer klick auf Checkliste */
Session.set("activeListId", e.target.id);
$("#"+e.target.id).siblings('li').removeClass("active");
$("#"+e.target.id).addClass("active");
},
'mouseover .clickOnList' : function (e,t) {
$( ".deleteLists" ).each(function( index, item ) {
if ( item.getAttribute("data-id") == e.target.getAttribute("data-id")) {
item.style.visibility = 'visible';
} else {
item.style.visibility = 'hidden';
}
});
},
'mouseleave .clickOnList' : function (e,t) {
$( ".deleteLists" ).each(function( index, item ) {
item.style.visibility = 'hidden';
});
},
'click .deleteLists' : function(e, t)
{
/* Eventhandler zum loeschen einer Checkliste */
var id = e.target.getAttribute("data-id");
Meteor.call("removeList", id);
console.log("test");
},
'click .changeListnameButton' : function(e,t) {
var id = e.target.getAttribute("data-id");
document.getElementById("changerForm_" + id).style.visibility = 'visible';
document.getElementById(id).style.visibility = 'hidden';
document.getElementById("changerText_" + id).focus();
},
'dblclick .clickOnList' : function(e,t){
var id = e.target.getAttribute("data-id");
document.getElementById("changerForm_" + id).style.visibility = 'visible';
document.getElementById(id).style.visibility = 'hidden';
document.getElementById("changerText_" + id).focus();
},
'submit .changeList-name-form' : function(e,t) {
e.preventDefault();
var id = e.target.getAttribute("data-id");
var text = document.getElementById("changerText_" + id).value;
if(text != '') {
Meteor.call("changeListName", id, text);
}
if (Session.get("activeListId", e.target.id) == id ) {
Session.set("activeListName", text);
}
document.getElementById("changerForm_" + id).style.visibility = 'hidden';
document.getElementById(id).style.visibility = 'visible';
},
'blur .list_name' : function(e,t) {
e.preventDefault();
var id = e.target.getAttribute("data-id");
var text = document.getElementById("changerText_" + id).value;
if((text != '') && (document.getElementById(id).style.visibility == 'hidden')) {
Meteor.call("changeListName", id, text);
}
if (Session.get("activeListId", e.target.id) == id ) {
Session.set("activeListName", text);
}
document.getElementById("changerForm_" + id).style.visibility = 'hidden';
document.getElementById(id).style.visibility = 'visible';
},
'click .userForListModal' : function(e,t) {
e.preventDefault();
activeListName = e.target.id;
activeListID = e.target.getAttribute("data-id");
//console.log(activeListID + " " + activeListName);
//console.log("New user for Liste" + Lists.findOne({_id : activeListID}).name);
userForList(activeListID);
$("#userForListModalLabel").html("Benutzer der Liste '"+ activeListName+ "'");
},
'submit #list-addUser-form' : function(e,t) {
e.preventDefault();
var newUser = $('#name-list-addUser').val();
Meteor.call("addUserToList", newUser, activeListID, function(error,result)
{
if (error) {
console.log(error.reason);
}
else
{
if (result == 1) {
$('#userForListModalerrorMessage').fadeIn(1000, function() {$(this).delay(1000).fadeOut(1000);});
$('#userForListModalerrorMessage').html("<div class=\"alert alert-danger\">Benutzer wurde nicht gefunden...</div>");
}
else if (result == 2) {
$('#userForListModalerrorMessage').fadeIn(1000, function() {$(this).delay(1000).fadeOut(1000);});
$('#userForListModalerrorMessage').html("<div class=\"alert alert-warning\">Benutzer ist Besitzer der Liste...</div>");
}
}
});
}
});
function userForList(id)
{
try
{
var owner = Lists.findOne({_id : id}).owner;
var members = Lists.findOne({_id : id}).member;
}
catch(e){
}
output = "<ul>";
output += "<li> Besitzer der Liste: <ul><li>" + owner + "</li></ul></li>";
output += "<li>Mitarbeiter der Liste: <ul>"
if (members != undefined) {
for(i=0; i<members.length; i++)
{
output+= "<li>" + members[i] + "</li>";
}
}
output += "</ul></li></ul>";
$('#userForListModalUsers').html(output);
}
main.js (server):
Lists = new Meteor.Collection("lists");
Meteor.publish("lists", function(){
var ListsOfUser = Meteor.users.findOne({_id : this.userId}).lists;
return Lists.find({_id :{ $in : ListsOfUser}});
});
Lists.allow({
insert : function(userID, list)
{
return (userID && (list.owner === userID));
},
//todo
update : function(userID)
{
return true;
},
//todo
remove : function(userID)
{
return true;
}
});
Thanks in advance!
I believe this is happening because the ListsOfUser variable in your Meteor.publish "lists" function is not a reactive data source. ListsOfUser is an array drawn from your result set, not a reactive cursor. Therefore it is not being invalidated server side when a user adds a new list on the client. From the Meteor docs (note the last sentence especially):
If you call Meteor.subscribe within a reactive computation, for example using
Deps.autorun,the subscription will automatically be cancelled when the computation
is invalidated or stopped; it's not necessary to call stop on subscriptions made
from inside autorun. However, if the next iteration of your run function subscribes
to the same record set (same name and parameters), Meteor is smart enough to skip a
wasteful unsubscribe/resubscribe.
ListsOfUser is not changing when a user adds a new list, so you are not being unsubscribed and resubscribed to the lists publication. (Note also that Meteor.users.findOne() is also not a reactive data source - you might want to switch it to Meteor.users.find() depending on how you go about making ListsOfUser reactive).
There are a few ways you could go about making the user lists reactive.
First, you could publish both the user cursor and the lists cursor, either separately or as an array in the same publish function, place both subscriptions in your Deps.autorun, and then fish out the user lists client side in a helper.
Meteor.publish("userWithLists", function(){
return Meteor.users.find(
{_id: this.userId},
{fields: {'lists': 1}}
);
});
Second, you could publish the static array of user lists as its own Collection and then use cursor.observe or cursor.observeChanges to track when it changes. While my understanding is that this is closest to the "correct" or "Meteor" way of doing it, it is also apparently quite verbose and I have not tried it. This tutorial goes into great detail about how you would tackle something like this: https://www.eventedmind.com/feed/aGHZygsphtTWELpKZ
Third, you could simply stick the user lists into your Session object, which is already reactive, and then publish your Lists.find() based on the Session, i.e.:
Meteor.publish("lists", function(lists){/* find code goes here */});
and
Deps.autorun(function(){
Meteor.subscribe("lists", Session.get("listsOfUser"));
});
This last one is probably an overuse / abuse of the Session object, particularly if your listsOfUser grows large, but should work as a hack.
I know this question is old, but still someone might be seeking for the answer. And the answer is Meteor.publishComposite available with a publish-composite package - https://atmospherejs.com/reywood/publish-composite
And there's an example there
Meteor.publishComposite('topTenPosts', {
find: function() {
// Find top ten highest scoring posts
return Posts.find({}, { sort: { score: -1 }, limit: 10 });
},
children: [
{
find: function(post) {
// Find post author. Even though we only want to return
// one record here, we use "find" instead of "findOne"
// since this function should return a cursor.
return Meteor.users.find(
{ _id: post.authorId },
{ limit: 1, fields: { profile: 1 } });
}
},
{
find: function(post) {
// Find top two comments on post
return Comments.find(
{ postId: post._id },
{ sort: { score: -1 }, limit: 2 });
},
children: [
{
find: function(comment, post) {
// Find user that authored comment.
return Meteor.users.find(
{ _id: comment.authorId },
{ limit: 1, fields: { profile: 1 } });
}
}
]
}
]
});
I am rather new to meteor but, in your server code, should it not be:
var ListsOfUser = Meteor.users.findOne({_id : Meteor.userId}).lists;
rather than:
var ListsOfUser = Meteor.users.findOne({_id : Meteor.userId}).lists;