Elasticsearch not analyzed is missing on index - c#

Every day I create the index on Elastic server which is hosted on AWS. Elastic Index format is abcnoteyyyyMMdd. You can look below the mapping result of Index.I am creating the index through ElasticSearch.Nest.
Index Creation Code:
DateTime _instance = DateTime.Now;
if (!(client.IndexExists("eccnote" + _instance.ToString("yyyyMMdd"))).Exists)
{
var createIndexResult = client.CreateIndex("eccnote" + _instance.ToString("yyyyMMdd"));
var mapResult = client.Map<ESNote>(c => c.MapFromAttributes().IgnoreConflicts().Type("esnote").Indices("eccnote" + _instance.ToString("yyyyMMdd")));
}
But there is some problem, I do not know what is it? An index is being created successfully. but someday I am getting "index" : "not_analyzed" is missing from mapping results. For example here is the mapping result of Index dated 20160615. Here the result is in a proper format.
GET **indexname20160615**/_mapping?pretty
output result:-
{
"indexname" : {
"mappings" : {
"type" : {
"properties" : {
"#timestamp" : {
"type" : "date",
"format" : "dateOptionalTime"
},
"account" : {
"type" : "string",
"index" : "not_analyzed"
},
"type" : {
"type" : "integer"
},
"userid" : {
"type" : "string",
"index" : "not_analyzed"
}
}
}
}
}
}
But when I see the mapping result of index dated 20160614,It is showing like this. Here "index" : "not_analyzed" properties is missing. It is happening for the random day only. I do not know why?
GET indexname20160614/_mapping?pretty
{
indexname20160614" : {
"mappings" : {
"indextype" : {
"properties" : {
"#timestamp" : {
"type" : "date",
"format" : "dateOptionalTime"
},
"session" : {
"type" : "string"
},
"tn" : {
"type" : "string"
},
"type" : {
"type" : "long"
},
"userid" : {
"type" : "string"
}
}
}
}
}
}
Why is it happening? Because every day through C# code, we create the index on ElasticServer but sometimes it is in proper format, sometimes it is not.

Related

UpdateMany - ArrayFilterDefinition c#

I'm trying to update just a few nested documents on my .Net Application, but I don't know exactly how to do that.
Here is one of the topics I've been searching after making this question:
C# - MongoDB - Update an element inside a Nested Document
**DataBase Object: **
{
"_id" : ObjectId("5d03a6f5fba276260c4911bd"),
"costumerId" : ObjectId("5c050cdefba2771eac58c84b"),
"order" : 106376,
"items" : [
{
"itemId" : 10226905,
"date" : ISODate("2018-11-30T14:00:00.000Z"),
"description" : "itemA",
"new" : true,
},
{
"itemId" : 10226906,
"date" : ISODate("2018-11-30T14:00:00.000Z"),
"description" : "itemB",
"new" : true,
},
{
"itemId" : 10226907,
"date" : ISODate("2018-11-23T14:00:00.000Z"),
"description" : "ItemC",
"new" : true,
},
{
"itemId" : 10226908,
"date" : ISODate("2018-11-23T14:00:00.000Z"),
"description" : "ItemD",
"new" : false,
},
]
}
MongoDB Update Query:
db.CostumerProducts.update(
{costumerId: 106376},
{
$set:{'items.$[element].new': true}
},
{
multi:true,
arrayFilters: [
{
'element.itemId':{
$in:[10226905,10226906,10226907]
}
}]
})
C# Update Query using MongoDB driver:
var arrayObjects = List<int>{10226905,10226906,10226907};
var filter = Builders<CostumerProductsObject>.Filter.And(new[]
{
new FilterDefinitionBuilder<CostumerProductsObject>().Eq(p=>p.costumerId, costumerId),
new FilterDefinitionBuilder<CostumerProductsObject>().Eq(p=>p.order, order),
});
var set = Builders<ItemsObject>.Update.Set("items.$[element].new", true);
var arrayFilter = new FilterDefinitionBuilder<ItemsObject>().In(a=>a.itemId, itemsArray);
using (var db = new MongoContextInfra())
{
db.Set<CostumerProductsObject>(CollectionName).UpdateMany(filter,
set,
new UpdateOptions
{
ArrayFilters = null
});
}
I expect to update just the three items into "arrayObjects" variable.
Can you show me some code or help me fixing mine so I can make this update?
thanks.

MongoDb - Joining ObjectId references in the list with related collections [duplicate]

I have the following MongoDb query working:
db.Entity.aggregate(
[
{
"$match":{"Id": "12345"}
},
{
"$lookup": {
"from": "OtherCollection",
"localField": "otherCollectionId",
"foreignField": "Id",
"as": "ent"
}
},
{
"$project": {
"Name": 1,
"Date": 1,
"OtherObject": { "$arrayElemAt": [ "$ent", 0 ] }
}
},
{
"$sort": {
"OtherObject.Profile.Name": 1
}
}
]
)
This retrieves a list of objects joined with a matching object from another collection.
Does anybody know how I can use this in C# using either LINQ or by using this exact string?
I tried using the following code but it can't seem to find the types for QueryDocument and MongoCursor - I think they've been deprecated?
BsonDocument document = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>("{ name : value }");
QueryDocument queryDoc = new QueryDocument(document);
MongoCursor toReturn = _connectionCollection.Find(queryDoc);
There is no need to parse the JSON. Everything here can actually be done directly with either LINQ or the Aggregate Fluent interfaces.
Just using some demonstration classes because the question does not really give much to go on.
Setup
Basically we have two collections here, being
entities
{ "_id" : ObjectId("5b08ceb40a8a7614c70a5710"), "name" : "A" }
{ "_id" : ObjectId("5b08ceb40a8a7614c70a5711"), "name" : "B" }
and others
{
"_id" : ObjectId("5b08cef10a8a7614c70a5712"),
"entity" : ObjectId("5b08ceb40a8a7614c70a5710"),
"name" : "Sub-A"
}
{
"_id" : ObjectId("5b08cefd0a8a7614c70a5713"),
"entity" : ObjectId("5b08ceb40a8a7614c70a5711"),
"name" : "Sub-B"
}
And a couple of classes to bind them to, just as very basic examples:
public class Entity
{
public ObjectId id;
public string name { get; set; }
}
public class Other
{
public ObjectId id;
public ObjectId entity { get; set; }
public string name { get; set; }
}
public class EntityWithOthers
{
public ObjectId id;
public string name { get; set; }
public IEnumerable<Other> others;
}
public class EntityWithOther
{
public ObjectId id;
public string name { get; set; }
public Other others;
}
Queries
Fluent Interface
var listNames = new[] { "A", "B" };
var query = entities.Aggregate()
.Match(p => listNames.Contains(p.name))
.Lookup(
foreignCollection: others,
localField: e => e.id,
foreignField: f => f.entity,
#as: (EntityWithOthers eo) => eo.others
)
.Project(p => new { p.id, p.name, other = p.others.First() } )
.Sort(new BsonDocument("other.name",-1))
.ToList();
Request sent to server:
[
{ "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
{ "$lookup" : {
"from" : "others",
"localField" : "_id",
"foreignField" : "entity",
"as" : "others"
} },
{ "$project" : {
"id" : "$_id",
"name" : "$name",
"other" : { "$arrayElemAt" : [ "$others", 0 ] },
"_id" : 0
} },
{ "$sort" : { "other.name" : -1 } }
]
Probably the easiest to understand since the fluent interface is basically the same as the general BSON structure. The $lookup stage has all the same arguments and the $arrayElemAt is represented with First(). For the $sort you can simply supply a BSON document or other valid expression.
An alternate is the newer expressive form of $lookup with a sub-pipeline statement for MongoDB 3.6 and above.
BsonArray subpipeline = new BsonArray();
subpipeline.Add(
new BsonDocument("$match",new BsonDocument(
"$expr", new BsonDocument(
"$eq", new BsonArray { "$$entity", "$entity" }
)
))
);
var lookup = new BsonDocument("$lookup",
new BsonDocument("from", "others")
.Add("let", new BsonDocument("entity", "$_id"))
.Add("pipeline", subpipeline)
.Add("as","others")
);
var query = entities.Aggregate()
.Match(p => listNames.Contains(p.name))
.AppendStage<EntityWithOthers>(lookup)
.Unwind<EntityWithOthers, EntityWithOther>(p => p.others)
.SortByDescending(p => p.others.name)
.ToList();
Request sent to server:
[
{ "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
{ "$lookup" : {
"from" : "others",
"let" : { "entity" : "$_id" },
"pipeline" : [
{ "$match" : { "$expr" : { "$eq" : [ "$$entity", "$entity" ] } } }
],
"as" : "others"
} },
{ "$unwind" : "$others" },
{ "$sort" : { "others.name" : -1 } }
]
The Fluent "Builder" does not support the syntax directly yet, nor do LINQ Expressions support the $expr operator, however you can still construct using BsonDocument and BsonArray or other valid expressions. Here we also "type" the $unwind result in order to apply a $sort using an expression rather than a BsonDocument as shown earlier.
Aside from other uses, a primary task of a "sub-pipeline" is to reduce the documents returned in the target array of $lookup. Also the $unwind here serves a purpose of actually being "merged" into the $lookup statement on server execution, so this is typically more efficient than just grabbing the first element of the resulting array.
Queryable GroupJoin
var query = entities.AsQueryable()
.Where(p => listNames.Contains(p.name))
.GroupJoin(
others.AsQueryable(),
p => p.id,
o => o.entity,
(p, o) => new { p.id, p.name, other = o.First() }
)
.OrderByDescending(p => p.other.name);
Request sent to server:
[
{ "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
{ "$lookup" : {
"from" : "others",
"localField" : "_id",
"foreignField" : "entity",
"as" : "o"
} },
{ "$project" : {
"id" : "$_id",
"name" : "$name",
"other" : { "$arrayElemAt" : [ "$o", 0 ] },
"_id" : 0
} },
{ "$sort" : { "other.name" : -1 } }
]
This is almost identical but just using the different interface and produces a slightly different BSON statement, and really only because of the simplified naming in the functional statements. This does bring up the other possibility of simply using an $unwind as produced from a SelectMany():
var query = entities.AsQueryable()
.Where(p => listNames.Contains(p.name))
.GroupJoin(
others.AsQueryable(),
p => p.id,
o => o.entity,
(p, o) => new { p.id, p.name, other = o }
)
.SelectMany(p => p.other, (p, other) => new { p.id, p.name, other })
.OrderByDescending(p => p.other.name);
Request sent to server:
[
{ "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
{ "$lookup" : {
"from" : "others",
"localField" : "_id",
"foreignField" : "entity",
"as" : "o"
}},
{ "$project" : {
"id" : "$_id",
"name" : "$name",
"other" : "$o",
"_id" : 0
} },
{ "$unwind" : "$other" },
{ "$project" : {
"id" : "$id",
"name" : "$name",
"other" : "$other",
"_id" : 0
}},
{ "$sort" : { "other.name" : -1 } }
]
Normally placing an $unwind directly following $lookup is actually an "optimized pattern" for the aggregation framework. However the .NET driver does mess this up in this combination by forcing a $project in between rather than using the implied naming on the "as". If not for that, this is actually better than the $arrayElemAt when you know you have "one" related result. If you want the $unwind "coalescence", then you are better off using the fluent interface, or a different form as demonstrated later.
Querable Natural
var query = from p in entities.AsQueryable()
where listNames.Contains(p.name)
join o in others.AsQueryable() on p.id equals o.entity into joined
select new { p.id, p.name, other = joined.First() }
into p
orderby p.other.name descending
select p;
Request sent to server:
[
{ "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
{ "$lookup" : {
"from" : "others",
"localField" : "_id",
"foreignField" : "entity",
"as" : "joined"
} },
{ "$project" : {
"id" : "$_id",
"name" : "$name",
"other" : { "$arrayElemAt" : [ "$joined", 0 ] },
"_id" : 0
} },
{ "$sort" : { "other.name" : -1 } }
]
All pretty familiar and really just down to functional naming. Just as with using the $unwind option:
var query = from p in entities.AsQueryable()
where listNames.Contains(p.name)
join o in others.AsQueryable() on p.id equals o.entity into joined
from sub_o in joined.DefaultIfEmpty()
select new { p.id, p.name, other = sub_o }
into p
orderby p.other.name descending
select p;
Request sent to server:
[
{ "$match" : { "name" : { "$in" : [ "A", "B" ] } } },
{ "$lookup" : {
"from" : "others",
"localField" : "_id",
"foreignField" : "entity",
"as" : "joined"
} },
{ "$unwind" : {
"path" : "$joined", "preserveNullAndEmptyArrays" : true
} },
{ "$project" : {
"id" : "$_id",
"name" : "$name",
"other" : "$joined",
"_id" : 0
} },
{ "$sort" : { "other.name" : -1 } }
]
Which actually is using the "optimized coalescence" form. The translator still insists on adding a $project since we need the intermediate select in order to make the statement valid.
Summary
So there are quite a few ways to essentially arrive at what is basically the same query statement with exactly the same results. Whilst you "could" parse the JSON to BsonDocument form and feed this to the fluent Aggregate() command, it's generally better to use the natural builders or the LINQ interfaces as they do easily map onto the same statement.
The options with $unwind are largely shown because even with a "singular" match that "coalescence" form is actually far more optimal then using $arrayElemAt to take the "first" array element. This even becomes more important with considerations of things like the BSON Limit where the $lookup target array could cause the parent document to exceed 16MB without further filtering. There is another post here on Aggregate $lookup Total size of documents in matching pipeline exceeds maximum document size where I actually discuss how to avoid that limit being hit by using such options or other Lookup() syntax available to the fluent interface only at this time.

MongoWriteException: A write operation resulted in an error. The positional operator did not find the match needed from the query

I have a collection Zonedetails shown below. below.
I am using C# to Insert or Update a Unit to Units array. If it is an insert I can insert Area blank. If it is an update It should only update the UnitName.
{
"Code" : "Zone1",
"Name" : "ZoneName1",
"Units" : [
{
"UnitCode" : "Unitcode1",
"UnitName" : "UnitCodeName",
"Areas" : [
{
"AreaCode" : "AreaCode1",
"AreaName" : "AreaName1"
}
]
}
]
}
{
"Code" : "Zone2",
"Name" : "ZoneName2",
"Units" : [
{
"UnitCode" : "UnitCode2",
"UnitName" : "UnityName2",
"Areas" : [
{
"AreaCode" : "Areacode2",
"AreaName" : "AreaName2"
}
]
}
]
}
{
"Code" : "Zone3",
"Name" : "ZoneName3",
"Units" : [
{
"UnitCode" : "UnitCode3",
"UnitName" : "UnitName3",
"Areas" : [
{
"AreaCode" : "Areadcode3",
"AreaName" : "AreaName3"
},
{
"AreaCode" : "AreaCode4",
"AreaName" : "Areaname4"
},
{
"AreaCode" : "AreaCode5",
"AreaName" : "Areaname5"
}
]
},
{
"UnitCode" : "UnitCode6",
"UnitName" : "UnitName6",
"Areas" : [
{
"AreaCode" : "AreaCode10",
"AreaName" : "AreaName10"
},
{
"AreaCode" : "AreaCOde11",
"AreaName" : "AreaName10"
},
{
"AreaCode" : "AreaCode12",
"AreaName" : "AreaName12"
}
]
}
]
}
I have writtent a C# code shown below. But getting "The positional operator did not find the match needed from the query"error if the Unit Code does not exist. Added not before unitCode check.
var mongoCollection = _context.GetCollection<Zone>("ZoneDetail");
var filter = Builders<Zone>.Filter.Where(x => x.Code == zoneCode && !x.Units.Any(u => u.UnitCode == unit.UnitCode));
var updateUnitCode = Builders<Zone>.Update.Set(x => x.Units.ElementAt(-1).UnitCode, unit.UnitCode);
var updateUnitName = Builders<Zone>.Update.Set(x => x.Units.ElementAt(-1).UnitName, unit.UnitName);
var result = await mongoCollection.UpdateOneAsync(filter, Builders<Zone>.Update.Combine(updateUnitCode, updateUnitName), new UpdateOptions { IsUpsert = true});
Your error message suggest that filter is not able to find matching element.
Either try to change your input or change your filter criteria.

MongoDb Query Array on C#

Im dba and development a C# Web App to get information from Mongodb, but when i try to get information from an array attribute, the C# show me all element of the document that contain the element that i find. I just want to get the specific element, not all.
I have this document:
{
"_id" : ObjectId("53b1b7dcb830980744687bd4"),
"i_nombre" : "Centro Comercial",
"i_direccion" : {
"i_d_pais" : "Panamá",
"i_d_ciudad" : "Panamá",
"i_d_provincia" : "Panamá",
"i_d_distrito" : "Chilibre",
"i_d_corregimiento" : "Alcalde Diaz",
"i_d_calle" : "Primera"
},
"i_correo_e" : "imqv#imqv.com.pa",
"i_telefono" : {
"i_t_iglesia" : "268-5000",
"i_t_colegio" : "268-5001",
"i_t_radio" : "268-5002"
},
"i_estado" : 1,
"i_sector" : [
{
"_id" : ObjectId("53b6d903b8309826e891eefe"),
"i_s_color" : "Amarillo",
"i_s_localizacion" : {
"i_s_l_provincia" : "Panamá",
"i_s_l_distrito" : "Chilibre",
"i_s_l_corregimiento" : "San Miguelito"
},
"i_s_supervisor" : []
},
{
"_id" : ObjectId("53b6d903b8309826e89100f0"),
"i_s_color" : "Rojo",
"i_s_localizacion" : {
"i_s_l_provincia" : "Panamá",
"i_s_l_distrito" : "Arraijan",
"i_s_l_corregimiento" : "Burunga"
},
"i_s_supervisor" : []
},
{
"_id" : ObjectId("53b6d903b8309826e89220f0"),
"i_s_color" : "Azul",
"i_s_localizacion" : {
"i_s_l_provincia" : "Panamá",
"i_s_l_distrito" : "Colon",
"i_s_l_corregimiento" : "Chilibre"
},
"i_s_supervisor" : []
}
]
};
When i execute this query on mongodb
db.iglesia.find
(
{ "_id" : ObjectId("53b1b7dcb830980744687bd4") }
, {
i_sector: {
$elemMatch: { "_id" : ObjectId("53b6d903b8309826e891eefe") }
}
}
);
i get:
{
"_id" : ObjectId("53b1b7dcb830980744687bd4"),
"i_sector" : [
{
"_id" : ObjectId("53b6d903b8309826e891eefe"),
"i_s_color" : "Amarillo",
"i_s_localizacion" : {
"i_s_l_provincia" : "Panamá",
"i_s_l_distrito" : "Chilibre",
"i_s_l_corregimiento" : "San Miguelito"
},
"i_s_supervisor" : []
}
]
}
Question: How i can get the same result with C#? Just with the $elemMatch that i set on Query.
The reason is that your Mongo shell query is not a find with 2 filters, by church id and sector, it is actually a find by church id and a projection by sector id. You have arranged the braces funny, that's all.
This has 2 filters and no projection:
db.iglesia.find ({"_id": "53b1b7dcb830980744687bd4", i_sector: { $elemMatch: {"_id" : "53b6d903b8309826e891eefe"}}}).pretty()
This has a filter and projection:
db.iglesia.find ({"_id": "53b1b7dcb830980744687bd4"}, {i_sector: { $elemMatch: { "_id": "53b6d903b8309826e891eefe"}}}).pretty()
A complete C# example, for these 2 cases using a newer driver, version 2.3, here on rextester.

Parsing JSON file C#

I have the following JSON that I want to parse into C#. I am trying to avoid outside libraries but if I have to I can use them. Right now I am using the JavaScriptSerializer method of parsing from a JSON file following the answer on another stackoverflow question Unfortunately I can have any number of the objectX items under Resources and they all have different names. Is there another way of doing this?
{
"FormatVersion" : "2010-09-09",
"Description" : "My JSON Description",
"Parameters" : {
"Product" : {
"Description" : "Product name",
"Type" : "String",
"Default" : "cs42"
},
"DifferentObjectSize" : {
"Description" : "DifferentObjectSize",
"Type" : "String",
"Default" : "large"
},
"ObjectSize" : {
"Description" : "Worker size",
"Type" : "String",
"Default" : "medium"
}
},
"Resources" : {
"differentobject" : {
"Type" : "MyType",
"Properties" : {
"InstanceType" : { "Ref" : "DifferentObjectSize" }
}
},
"object1" : {
"Type" : "MyType",
"Properties" : {
"InstanceType" : { "Ref" : "ObjectSize" }
}
},
"object2" : {
"Type" : "MyType",
"Properties" : {
"InstanceType" : { "Ref" : "ObjectSize" }
}
},
"object3" : {
"Type" : "MyType",
"Properties" : {
"InstanceType" : { "Ref" : "ObjectSize" }
}
},
"object4" : {
"Type" : "MyType",
"Properties" : {
"InstanceType" : { "Ref" : "ObjectSize" }
}
},
}
}
If you think to use Json.Net you can parse your input string as below
JObject myObj = (JObject)JsonConvert.DeserializeObject(jsonString);
foreach(var resource in myObj["Resources"])
{
var props = resource.Children<JObject>().First();
Console.WriteLine(props["Type"] + " " + props["Properties"]["InstanceType"]["Ref"]);
}

Categories

Resources