mongodb find where columns of arrays don't match - arrays

i am looking for a possible solution to find results from a mongodb collection where two columns of arrays don't hold the same entries.
Something like this:
Message DB structure
{
id: ObjectId,
title: String,
body: String,
recipients: [{ObjectId, ref: 'User'}],
visualized_by: [{ObjectId, ref: 'User'}]
}
when a User visualizes the message his id gets stored in the visualized_by column
Now, from an admin panel I want to visualize only the messages that were not seen by all the recipients like this:
Message.find({recipients: {$each: {$nin: "$visualized_by"}}})
OR
Message.find({$where: {recipients: {$each: {$nin: this.visualized_by}}}})
But it does not work of course.
Any help will be appreciated.
Thanks!

Related

MongoDB find in array in all documents

I have a collection of documents with this simplified structure:
{
cards: [
{
id: "some string",
....
},{...}{...}{...}
]
}
I need to query the whole collection of documents and find those documents where my defined ID of a card matches one of the objects in the array of cards.
I usually fetch all documents and do it locally but this is quite large collection and I have no clue how to achieve this if even possible.
Thank you for your time!
ps: I'm using nodejs mongoose
After playing around with mohammad Naimi's solution I figured the correct syntax:
db.collection.find({ cards:{ $elemMatch: { id: { $eq:"some string" }}}})
db.collection.find({cards:{$elemMatch:{id:{$eq:"some string"}}})

Mongoose: (CastError) Cast to [ObjectId] failed for value

I'm having a lil problem I've been trying to solve for a while and despite looking online pretty much everywhere I can't find the solution to my problem.
I have 2 mongoose schemas. One "Post" schema and one "Tag" schema.
const postSchema = new Schema({
creator:{type:mongoose.Types.ObjectId, required:true, ref:'User'},
type:{type:String, required:true},
title:{type:String, maxlength:14},
description:{type:String, maxlength:1140},
content:{type:String},
tags:[{type:mongoose.Types.ObjectId, ref:'Tag'}],
date:{type:Date},
});
const tagSchema = new Schema({
name:{type:String, required:true, unique:true},
bgImages:[{type:String}],
posts:[{type:mongoose.Types.ObjectId, ref:'Post'}],
});
When I create a new post, I want to be able to add multiple tags to the tags array in the Post, so what I tried doing is find the ID's of the tags selected by the user and send the array of id's in the POST request.
This is the exact error I get:
'tags.0': CastError: Cast to [ObjectId] failed for value "["60d193ab04caf9336cc9169b,60d193b504caf9336cc9169c"]" (type string) at path "tags.0"
Both the ID's exist in the Tag collection. If I send only one Id in the request it works, but if I send an array of Id's it doesn't.
Something I have in mind is that it sends an array of a single string from what looks like, instead of an array of strings (where each string is the ID).
Can someone help me figure out what's the issue? Thanks a lot.
Found the problem. As I thought it's because I was sending an array containing one single string instead of an array of atomic strings.
Had to split the array with "," to solve the problem.

Meteor inserting into a collection schema with array elements

Hi I created a SimpleSchema for a Mongo collection which has a variable number of sub-documents called measurables. Unfortunately it's been a while since I've done this and I can't remember how to insert into this type of schema! Can someone help me out?
The schema is as follows:
const ExerciseTemplates = new Mongo.Collection('ExerciseTemplates');
const ExerciseTemplateSchema = new SimpleSchema({
name: {
type: String,
label: 'name',
},
description: {
type: String,
label: 'description',
},
createdAt: {
type: Date,
label: 'date',
},
measurables: {
type: Array,
minCount: 1,
},
'measurables.$': Object,
'measurables.$.name': String,
'measurables.$.unit': String,
});
ExerciseTemplates.attachSchema(ExerciseTemplateSchema);
The method is:
Meteor.methods({
addNewExerciseTemplate(name, description, measurables) {
ExerciseTemplates.insert({
name,
description,
createdAt: new Date(),
measurables,
});
},
});
The data sent by my form for measurables is an array of objects.
The SimpleSchema docs seem to be out of date. If I use the example they show with measurables: type: [Object] for an array of objects. I get an error that the the type can't be an array and I should set it to Array.
Any suggestions would be awesome!!
Many thanks in advance!
edit:
The measurable variable contains the following data:
[{name: weight, unit: kg}]
With the schema above I get no error at all, it is silent as if it was successful, but when I check the db via CLI I have no collections. Am I doing something really stupid? When I create a new meteor app, it creates a Mongo db for me I assume - I'm not forgetting to actually create a db or something dumb?
Turns out I was stupid. The schema I posted was correct and works exactly as intended. The problem was that I defined my schema and method in a file in my imports directory, outside both client and server directories. This methods file was imported into the file with the form that calls the method, and therefore available on the client, but not imported into the server.
I guess that the method was being called on the client as a stub so I saw the console.log firing, but the method was not being called on the server therefore not hitting the db.
Good lesson for me regarding the new recommended file structure. Always import server side code in server/main.js!!! :D
Thanks for your help, thought I was going to go mad!

How to publish a mongodb array length as an additional collection field?

I have a mongodb collection with the following fields:
_id
name (string)
[items] (array of string)
secret (boolean)
I want to publish the all the _id, name fields and the item array length only (excluding the secret field) where the secret field is true.
I have read somewhere that I can add additional document properties in my find query, but my google foo does not work.
Here is what my publish method looks like without the additional items_count property:
Meteor.publish("all_items", function() {
return myItems.find(
{secret: true},
{fields:
{_id:1,name:1}
});
});
How can I create an additional field from the [item] length in my publication?
EDIT: it seems that I need to use an aggregate function and the $projectoperator. And it is not supported by meteor.
Can anyone confirm this to me (i.e. it is the only option and it is not supported)?
You can add aggregation framework support to Meteor, and then use a simple aggregation pipeline with $project stage as you mentioned, like to following:
myItems.aggregate(
[
{$match: {secret: true}},
{$project: {_id: 1, name: 1, items_count: {$size: '$items'}}}
]
)

MongoDB: Query and retrieve objects inside embedded array?

Let's say I have the following document schema in a collection called 'users':
{
name: 'John',
items: [ {}, {}, {}, ... ]
}
The 'items' array contains objects in the following format:
{
item_id: "1234",
name: "some item"
}
Each user can have multiple items embedded in the 'items' array.
Now, I want to be able to fetch an item by an item_id for a given user.
For example, I want to get the item with id "1234" that belong to the user with name "John".
Can I do this with mongoDB? I'd like to utilize its powerful array indexing, but I'm not sure if you can run queries on embedded arrays and return objects from the array instead of the document that contains it.
I know I can fetch users that have a certain item using {users.items.item_id: "1234"}. But I want to fetch the actual item from the array, not the user.
Alternatively, is there maybe a better way to organize this data so that I can easily get what I want? I'm still fairly new to mongodb.
Thanks for any help or advice you can provide.
The question is old, but the response has changed since the time. With MongoDB >= 2.2, you can do :
db.users.find( { name: "John"}, { items: { $elemMatch: { item_id: "1234" } } })
You will have :
{
name: "John",
items:
[
{
item_id: "1234",
name: "some item"
}
]
}
See Documentation of $elemMatch
There are a couple of things to note about this:
1) I find that the hardest thing for folks learning MongoDB is UN-learning the relational thinking that they're used to. Your data model looks to be the right one.
2) Normally, what you do with MongoDB is return the entire document into the client program, and then search for the portion of the document that you want on the client side using your client programming language.
In your example, you'd fetch the entire 'user' document and then iterate through the 'items[]' array on the client side.
3) If you want to return just the 'items[]' array, you can do so by using the 'Field Selection' syntax. See http://www.mongodb.org/display/DOCS/Querying#Querying-FieldSelection for details. Unfortunately, it will return the entire 'items[]' array, and not just one element of the array.
4) There is an existing Jira ticket to add this functionality: it is https://jira.mongodb.org/browse/SERVER-828 SERVER-828. It looks like it's been added to the latest 2.1 (development) branch: that means it will be available for production use when release 2.2 ships.
If this is an embedded array, then you can't retrieve its elements directly. The retrieved document will have form of a user (root document), although not all fields may be filled (depending on your query).
If you want to retrieve just that element, then you have to store it as a separate document in a separate collection. It will have one additional field, user_id (can be part of _id). Then it's trivial to do what you want.
A sample document might look like this:
{
_id: {user_id: ObjectId, item_id: "1234"},
name: "some item"
}
Note that this structure ensures uniqueness of item_id per user (I'm not sure you want this or not).

Resources